Skip to content

fail ​

Function, in @jr2/orchestrator/src/fail.ts. It is an export of @jr2/orchestrator, on the Authoring surface 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 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

The docs of Kit version 0.5.1. Each page is also at its .md URL.