---
title: PreconditionFailedError
description: World implementations throw this error when they reject an event creation because the client's event-log snapshot is stale.
type: reference
summary: Catch PreconditionFailedError when a World rejects an event creation made from a stale event-log snapshot.
related:
  - /docs/api-reference/workflow-errors/workflow-world-error
  - /docs/api-reference/workflow-errors/entity-conflict-error
---

# PreconditionFailedError



World implementations throw `PreconditionFailedError` when they reject an event creation because the client's event-log snapshot is stale: the log already held more events than the position the creation named. It corresponds to HTTP 412 Precondition Failed semantics.

No World in this repository throws it. A stale replay does not need to be refused: its log is a prefix rather than a prefix with a hole in it, replay is deterministic on a prefix, and the write it makes next comes back carrying the events it was pushed past (see [Stale reads](/docs/configuration/runtime-tuning#stale-reads-and-why-nothing-has-to-be-rejected)). The error and the runtime's handling of it remain for a World that would rather refuse than report. Such a World allocates positions somewhere other than the commit, so it cannot report a gap reliably. Event creations that carry no position are never rejected with it.

A World rejects only on evidence and accepts the creation whenever it cannot decide. This error always means the snapshot was stale, but not receiving it does not prove the snapshot was current.

<Callout>
  The Workflow runtime handles this error by restarting the replay in the same invocation from a corrected event log. It re-invokes the run for a fresh replay only after spending its in-process restart budget. It never retries the rejected creation as-is because a replay working from a corrected log derives different events. You will only encounter it when interacting with World storage APIs directly.
</Callout>

A World may attach the events the client was missing to the rejection as `details`, which lets the runtime restart without re-reading the event log. This is optional, and the runtime falls back to a full reload when the details are absent or unusable.

```typescript lineNumbers
import { PreconditionFailedError } from "workflow/errors"
declare const world: { events: { create(...args: any[]): Promise<any> } }; // @setup
declare const runId: string; // @setup
declare const event: any; // @setup

try {
  await world.events.create(runId, event);
} catch (error) {
  if (PreconditionFailedError.is(error)) { // [!code highlight]
    console.log("Snapshot is stale; reload the event log and retry");
  }
}
```

## API signature

### Properties

<TSDoc
  definition={`
interface PreconditionFailedError {
/** Delay in seconds before the operation should be retried. Present when the server sends a Retry-After header. */
retryAfter?: number;
/** Optional rejection payload. A world may put the events the client was missing here, as \`{ events, cursor }\`, so the runtime can restart its replay without re-reading the event log. */
details?: unknown;
/** The error message. */
message: string;
}
export default PreconditionFailedError;`}
/>

### Static methods

#### `PreconditionFailedError.is(value)`

Type-safe check for `PreconditionFailedError` instances. Preferred over `instanceof` because it works across module boundaries and VM contexts.

```typescript
import { PreconditionFailedError } from "workflow/errors"
declare const error: unknown; // @setup

if (PreconditionFailedError.is(error)) {
  // error is typed as PreconditionFailedError
}
```


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)