---
title: fail
description: "Fail the run: the Part a Machine invokes to end work that did not succeed."
---

# `fail`

Function, in `@jr2/orchestrator/src/fail.ts`. It is an export of `@jr2/orchestrator`, on the [Authoring surface](../authoring-surface.md) page, in Failure.

```ts
function fail(): FailSlot
```

Fail the run: the Part a Machine invokes to end work that did not succeed. Put it in `actors`
under a name, and invoke it from any state, at any depth: `actors: { fail: fail() }`, then
`invoke: { src: "fail", input: { reason } }`.

The input is `{ reason: string; detail?: unknown }`. `reason` is text for a person, and it must
not be empty. `detail` is optional JSON for a machine reader.

The Failure goes up from the state that invokes `fail`, through each parent Machine, as an error
does. An `onError` on the way catches it; [`isFailure`](isfailure.md) tells it from a defect. When no state
catches it, the run ends `failed`: its output is `{ reason, detail }`, and `jr2 run` exits 1. A
`workspace()` that a Failure goes through deletes its Sandbox first.

To fail, invoke `fail`. Do not throw from a promise to fail: a throw is a defect, and the run
ends `error`. A final state means `done`: do not use one for work that did not succeed. To keep
the work for a person to read, wait at a Gate before the state that fails.

It refuses an input that is not a Failure's, and the run ends `error`: ``fail: the input must be
{ reason: string; detail?: unknown } with a reason that is not empty (got <value>) — invoke:
{ src: "fail", input: { reason: "the tests failed" } } (ADR-0073)``.

**Returns**: The actor logic of the slot.

**Example**

```ts
import { z } from "zod";
import { command, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";

const runInput = z.object({ branch: z.string() });

const body = jr2Setup({
  types: {} as { input: Workspaced<z.infer<typeof runInput>, "app"> },
  actors: {
    tests: command(["npm", "test"], { timeout: "15m" }),
    fail: fail(),
  },
}).createMachine({
  id: "check",
  on: { "workspace.lost": ".lost" },
  initial: "testing",
  states: {
    testing: {
      invoke: {
        src: "tests",
        onDone: [
          {
            guard: ({ event }) => event.output.outcome === "exited" && event.output.code === 0,
            target: "passed",
          },
          { target: "failing" },
        ],
      },
    },
    // Not a final state: the run ends `failed`, and the Workspace deletes the Sandbox.
    failing: { invoke: { src: "fail", input: { reason: "npm test did not pass" } } },
    passed: { type: "final" },
    lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
  },
});

export const machine = workspace(body, {
  input: runInput,
  repos: { app: "https://github.com/you/app.git" },
  spec: ({ input }) => ({ branch: input.branch }),
});
```

**See also**

- [ADR-0073: A Machine fails a run with `fail()`, and an uncaught Failure ends it `failed`](../decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md)
