---
title: "Failures and cleanup — no Effect required"
image: "https://hem.run/social/hem.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://hem.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Failures and cleanup — no Effect required

The failure vocabulary is core, and plain Hem already provides structured error handling. `error` declares a tagged error class:

```hem title="errors.hem"
error QuotaExceeded({ orgId: string })
```

```ts emitted title="errors.ts — generated"
class QuotaExceeded extends Error {
  readonly _tag = "QuotaExceeded";
  readonly orgId: string;

  constructor(fields: { readonly orgId: string }) {
super("QuotaExceeded");
this.name = "QuotaExceeded";
this.orgId = fields.orgId;
  }
}
```

A declared `cause` or `message` field forwards to `super`; `export error` exports the class. A statement that only drops a value is refused (HEM2018): a bare `push(tx, doc)` that returns a `Promise` and is never awaited, or a bare comparison, is almost always a mistake: `await` it, use the value, or discard it on purpose with `let _ = push(tx, doc)`. That discard emits `void (push(tx, doc));`, so strict TypeScript and no-floating-Promise rules see the intent without an unused local.

`raise` throws one (inserting `new` for locally declared error types), and postfix `catch` handles: tag arms test with `instanceof`, a binding arm `e => …` catches everything, and (the rule that makes it composable) **anything unmatched propagates**. These are JavaScript exceptions: the error _values_ are typed, but a raise leaves no trace in the function's type, so callers are not made to handle it. When a failure belongs in the signature, return a `Result<T, E>` (§19) or move to Effect (§17):

```hem title="save.hem"
error SaveFailed({ doc: string })

let save = async (doc: Doc) => {
  use tx = db.begin()                     // released at block exit — even on throw
  await push(tx, doc) catch {
  | QuotaExceeded(_) => cached(doc)
  | _ => raise SaveFailed({ doc: doc.id })
  }
}
```

```ts emitted title="save.ts — generated"
class SaveFailed extends Error {
  readonly _tag = "SaveFailed";
  readonly doc: string;

  constructor(fields: { readonly doc: string }) {
super("SaveFailed");
this.name = "SaveFailed";
this.doc = fields.doc;
  }
}
const save = async (doc: Doc) => {
  using tx = db.begin(); // released at block exit — even on throw
  let _hemValue;
  try {
_hemValue = await push(tx, doc);
  } catch (error) {
if (error instanceof QuotaExceeded) {
  _hemValue = cached(doc);
} else {
  throw new SaveFailed({ doc: doc.id });
}
  }
  return _hemValue;
};
```

(An `AsyncDisposable` transaction would lower to `await using`; the checker decides per resource.)

`use` binds a _resource_: in plain code that means `Disposable`/`AsyncDisposable`, lowered to the platform's `using`/`await using`, which Workers RPC stubs and Durable Object handles speak natively. `try { }` still exists for multi-statement protected regions, but postfix `catch` is the idiomatic form; it attaches to any expression, `await` included. In Part II these same keywords change _transport_ (errors travel down a typed channel instead of up the stack, so the types start recording them, and releases survive interruption) without changing a line of what you just learned.

Source: https://hem.run/tour/failures-and-cleanup-no-effect-required/index.mdx
