workflow 4.2.0-beta.70 → 4.2.0-beta.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/api.d.ts +1 -1
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js +1 -1
  4. package/dist/internal/builtins.d.ts +3 -3
  5. package/dist/internal/builtins.d.ts.map +1 -1
  6. package/dist/internal/builtins.js +7 -7
  7. package/dist/internal/errors.d.ts +1 -1
  8. package/dist/internal/errors.d.ts.map +1 -1
  9. package/dist/internal/errors.js +2 -2
  10. package/dist/observability.d.ts +20 -0
  11. package/dist/observability.d.ts.map +1 -0
  12. package/dist/observability.js +20 -0
  13. package/docs/ai/chat-session-modeling.mdx +4 -4
  14. package/docs/ai/defining-tools.mdx +7 -1
  15. package/docs/ai/index.mdx +8 -5
  16. package/docs/ai/message-queueing.mdx +8 -6
  17. package/docs/ai/resumable-streams.mdx +37 -4
  18. package/docs/ai/sleep-and-delays.mdx +2 -0
  19. package/docs/api-reference/index.mdx +3 -0
  20. package/docs/api-reference/meta.json +1 -1
  21. package/docs/api-reference/workflow/define-hook.mdx +2 -0
  22. package/docs/api-reference/workflow/get-writable.mdx +1 -0
  23. package/docs/api-reference/workflow-ai/durable-agent.mdx +7 -5
  24. package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +2 -0
  25. package/docs/api-reference/workflow-api/get-run.mdx +14 -0
  26. package/docs/api-reference/workflow-api/get-world.mdx +105 -0
  27. package/docs/api-reference/workflow-api/start.mdx +24 -0
  28. package/docs/api-reference/workflow-errors/entity-conflict-error.mdx +60 -0
  29. package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +90 -0
  30. package/docs/api-reference/workflow-errors/meta.json +16 -0
  31. package/docs/api-reference/workflow-errors/run-expired-error.mdx +58 -0
  32. package/docs/api-reference/workflow-errors/step-not-registered-error.mdx +56 -0
  33. package/docs/api-reference/workflow-errors/throttle-error.mdx +62 -0
  34. package/docs/api-reference/workflow-errors/too-early-error.mdx +62 -0
  35. package/docs/api-reference/workflow-errors/workflow-not-registered-error.mdx +57 -0
  36. package/docs/api-reference/workflow-errors/workflow-run-cancelled-error.mdx +56 -0
  37. package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +62 -0
  38. package/docs/api-reference/workflow-errors/workflow-run-not-found-error.mdx +56 -0
  39. package/docs/api-reference/workflow-errors/workflow-world-error.mdx +79 -0
  40. package/docs/api-reference/workflow-serde/index.mdx +52 -0
  41. package/docs/api-reference/workflow-serde/meta.json +3 -0
  42. package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +70 -0
  43. package/docs/api-reference/workflow-serde/workflow-serialize.mdx +75 -0
  44. package/docs/changelog/index.mdx +15 -0
  45. package/docs/changelog/meta.json +5 -0
  46. package/docs/deploying/building-a-world.mdx +20 -0
  47. package/docs/deploying/world/vercel-world.mdx +2 -1
  48. package/docs/errors/hook-conflict.mdx +9 -3
  49. package/docs/errors/index.mdx +6 -0
  50. package/docs/errors/step-not-registered.mdx +66 -0
  51. package/docs/errors/webhook-invalid-respond-with-value.mdx +10 -0
  52. package/docs/errors/webhook-response-not-sent.mdx +8 -0
  53. package/docs/errors/workflow-not-registered.mdx +64 -0
  54. package/docs/foundations/common-patterns.mdx +4 -0
  55. package/docs/foundations/errors-and-retries.mdx +29 -0
  56. package/docs/foundations/serialization.mdx +211 -0
  57. package/docs/foundations/streaming.mdx +22 -0
  58. package/docs/getting-started/index.mdx +3 -3
  59. package/docs/getting-started/meta.json +15 -0
  60. package/docs/getting-started/nestjs.mdx +4 -8
  61. package/docs/how-it-works/encryption.mdx +93 -0
  62. package/docs/how-it-works/meta.json +2 -1
  63. package/docs/observability/index.mdx +3 -0
  64. package/package.json +18 -12
@@ -0,0 +1,79 @@
1
+ ---
2
+ title: WorkflowWorldError
3
+ description: Base error for failures from workflow storage backends.
4
+ type: reference
5
+ summary: Catch WorkflowWorldError to handle any error originating from a workflow world (storage backend).
6
+ related:
7
+ - /docs/api-reference/workflow-errors/entity-conflict-error
8
+ - /docs/api-reference/workflow-errors/run-expired-error
9
+ - /docs/api-reference/workflow-errors/too-early-error
10
+ - /docs/api-reference/workflow-errors/throttle-error
11
+ ---
12
+
13
+ `WorkflowWorldError` is the base error class for failures originating from a workflow world (storage backend). World implementations (local, Postgres, Vercel) throw subclasses of this error when storage operations fail.
14
+
15
+ You can use `instanceof WorkflowWorldError` to catch any world-related error regardless of the specific type. Note that the static `.is()` method only matches errors constructed directly as `WorkflowWorldError` — use the subclass-specific `.is()` methods (e.g. `EntityConflictError.is()`) to match specific error types.
16
+
17
+ <Callout>
18
+ Most world errors are handled automatically by the Workflow runtime. You will typically only encounter these errors when interacting with world storage APIs directly or when there are infrastructure-level issues.
19
+ </Callout>
20
+
21
+ ```typescript lineNumbers
22
+ import { WorkflowWorldError } from "workflow/errors"
23
+ declare const world: { events: { create(...args: any[]): Promise<any> } }; // @setup
24
+ declare const runId: string; // @setup
25
+ declare const event: any; // @setup
26
+
27
+ try {
28
+ await world.events.create(runId, event);
29
+ } catch (error) {
30
+ if (error instanceof WorkflowWorldError) { // [!code highlight]
31
+ console.error("Storage backend error:", error.message);
32
+ }
33
+ }
34
+ ```
35
+
36
+ ## API Signature
37
+
38
+ ### Properties
39
+
40
+ <TSDoc
41
+ definition={`
42
+ interface WorkflowWorldError {
43
+ /** HTTP status code from the world backend, if available. */
44
+ status?: number;
45
+ /** Machine-readable error code, if available. */
46
+ code?: string;
47
+ /** The URL that was requested, if available. */
48
+ url?: string;
49
+ /** Retry-After value in seconds, present on 429 and 425 responses. */
50
+ retryAfter?: number;
51
+ /** The error message. */
52
+ message: string;
53
+ }
54
+ export default WorkflowWorldError;`}
55
+ />
56
+
57
+ ### Static Methods
58
+
59
+ #### `WorkflowWorldError.is(value)`
60
+
61
+ Type-safe check that matches only errors constructed directly as `WorkflowWorldError`. Does not match subclasses like `EntityConflictError` — use `instanceof` to catch all world errors, or the subclass-specific `.is()` methods.
62
+
63
+ ```typescript
64
+ import { WorkflowWorldError } from "workflow/errors"
65
+ declare const error: unknown; // @setup
66
+
67
+ if (WorkflowWorldError.is(error)) {
68
+ // error is typed as WorkflowWorldError (not subclasses)
69
+ }
70
+ ```
71
+
72
+ ### Subclasses
73
+
74
+ The following error types extend `WorkflowWorldError`:
75
+
76
+ - [`EntityConflictError`](/docs/api-reference/workflow-errors/entity-conflict-error) — operation conflicts with entity state
77
+ - [`RunExpiredError`](/docs/api-reference/workflow-errors/run-expired-error) — run has expired
78
+ - [`TooEarlyError`](/docs/api-reference/workflow-errors/too-early-error) — request made before system is ready
79
+ - [`ThrottleError`](/docs/api-reference/workflow-errors/throttle-error) — request was rate-limited
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: "@workflow/serde"
3
+ ---
4
+
5
+ Serialization symbols for custom class serialization in Workflow DevKit.
6
+
7
+ ## Installation
8
+
9
+ ```package-install
10
+ npm i @workflow/serde
11
+ ```
12
+
13
+ ## Overview
14
+
15
+ By default, Workflow DevKit can serialize standard JavaScript types like primitives, objects, arrays, `Date`, `Map`, `Set`, and more. However, custom class instances are not serializable by default because the serialization system doesn't know how to reconstruct them.
16
+
17
+ The `@workflow/serde` package provides two symbols that allow you to define custom serialization and deserialization logic for your classes, enabling them to be passed between workflow and step functions.
18
+
19
+ ## Symbols
20
+
21
+ <Cards>
22
+ <Card href="/docs/api-reference/workflow-serde/workflow-serialize" title="WORKFLOW_SERIALIZE">
23
+ Symbol for defining how to serialize a class instance to plain data.
24
+ </Card>
25
+ <Card href="/docs/api-reference/workflow-serde/workflow-deserialize" title="WORKFLOW_DESERIALIZE">
26
+ Symbol for defining how to reconstruct a class instance from plain data.
27
+ </Card>
28
+ </Cards>
29
+
30
+ ## Quick Example
31
+
32
+ {/* @expect-error:2351 */}
33
+
34
+ ```typescript lineNumbers
35
+ import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde";
36
+
37
+ class Point {
38
+ constructor(public x: number, public y: number) {}
39
+
40
+ static [WORKFLOW_SERIALIZE](instance: Point) {
41
+ return { x: instance.x, y: instance.y };
42
+ }
43
+
44
+ static [WORKFLOW_DESERIALIZE](data: { x: number; y: number }) {
45
+ return new Point(data.x, data.y);
46
+ }
47
+ }
48
+ ```
49
+
50
+ <Callout>
51
+ For a complete guide on custom class serialization, see the [Serialization documentation](/docs/foundations/serialization#custom-class-serialization).
52
+ </Callout>
@@ -0,0 +1,3 @@
1
+ {
2
+ "pages": ["...", "workflow-serialize", "workflow-deserialize"]
3
+ }
@@ -0,0 +1,70 @@
1
+ ---
2
+ title: WORKFLOW_DESERIALIZE
3
+ ---
4
+
5
+ A symbol used to define custom deserialization for user-defined class instances. The static method should accept serialized data and return a new class instance.
6
+
7
+ ## Usage
8
+
9
+ {/* @expect-error:2351 */}
10
+
11
+ ```typescript lineNumbers
12
+ import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde";
13
+
14
+ class Point {
15
+ constructor(public x: number, public y: number) {}
16
+
17
+ static [WORKFLOW_SERIALIZE](instance: Point) {
18
+ return { x: instance.x, y: instance.y };
19
+ }
20
+
21
+ static [WORKFLOW_DESERIALIZE](data: { x: number; y: number }) {
22
+ return new Point(data.x, data.y);
23
+ }
24
+ }
25
+ ```
26
+
27
+ ## API Signature
28
+
29
+ {/* @skip-typecheck */}
30
+
31
+ ```typescript
32
+ static [WORKFLOW_DESERIALIZE](data: SerializableData): T
33
+ ```
34
+
35
+ ### Parameters
36
+
37
+ <TSDoc
38
+ definition={`
39
+ interface Parameters {
40
+ /**
41
+ * The serialized data to reconstruct into a class instance.
42
+ * This is the same data that was returned by WORKFLOW_SERIALIZE.
43
+ */
44
+ data: SerializableData;
45
+ }
46
+ export default Parameters;`}
47
+ />
48
+
49
+ ### Returns
50
+
51
+ The method should return a new instance of the class, reconstructed from the serialized data.
52
+
53
+ ## Requirements
54
+
55
+ <Callout type="warn">
56
+ The method must be implemented as a **static** method on the class. Instance methods are not supported.
57
+ </Callout>
58
+
59
+ - Both `WORKFLOW_SERIALIZE` and `WORKFLOW_DESERIALIZE` must be implemented together
60
+ - The method receives the exact data that was returned by `WORKFLOW_SERIALIZE`
61
+ - If `WORKFLOW_SERIALIZE` returns complex types (like `Map` or `Date`), they will be properly deserialized before being passed to this method
62
+
63
+ <Callout type="warn">
64
+ This method runs inside the workflow context and is subject to the same constraints as `"use workflow"` functions:
65
+ - No Node.js-specific APIs (like `fs`, `path`, `crypto`, etc.)
66
+ - No non-deterministic operations (like `Math.random()` or `Date.now()`)
67
+ - No external network calls
68
+
69
+ Keep this method simple and focused on reconstructing the instance from the provided data.
70
+ </Callout>
@@ -0,0 +1,75 @@
1
+ ---
2
+ title: WORKFLOW_SERIALIZE
3
+ ---
4
+
5
+ A symbol used to define custom serialization for user-defined class instances. The static method should accept an instance and return serializable data.
6
+
7
+ ## Usage
8
+
9
+ {/* @expect-error:2351 */}
10
+
11
+ ```typescript lineNumbers
12
+ import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde";
13
+
14
+ class Point {
15
+ constructor(public x: number, public y: number) {}
16
+
17
+ static [WORKFLOW_SERIALIZE](instance: Point) {
18
+ return { x: instance.x, y: instance.y };
19
+ }
20
+
21
+ static [WORKFLOW_DESERIALIZE](data: { x: number; y: number }) {
22
+ return new Point(data.x, data.y);
23
+ }
24
+ }
25
+ ```
26
+
27
+ ## API Signature
28
+
29
+ {/* @skip-typecheck */}
30
+
31
+ ```typescript
32
+ static [WORKFLOW_SERIALIZE](instance: T): SerializableData
33
+ ```
34
+
35
+ ### Parameters
36
+
37
+ <TSDoc
38
+ definition={`
39
+ interface Parameters {
40
+ /**
41
+ * The class instance to serialize.
42
+ */
43
+ instance: T;
44
+ }
45
+ export default Parameters;`}
46
+ />
47
+
48
+ ### Returns
49
+
50
+ The method should return serializable data. This can be:
51
+
52
+ - Primitives (`string`, `number`, `boolean`, `null`, `undefined`, `bigint`)
53
+ - Plain objects with serializable values
54
+ - Arrays of serializable values
55
+ - Built-in serializable types (`Date`, `Map`, `Set`, `RegExp`, `URL`, etc.)
56
+ - Other custom classes that implement serialization
57
+
58
+ ## Requirements
59
+
60
+ <Callout type="warn">
61
+ The method must be implemented as a **static** method on the class. Instance methods are not supported.
62
+ </Callout>
63
+
64
+ - Both `WORKFLOW_SERIALIZE` and `WORKFLOW_DESERIALIZE` must be implemented together
65
+ - The returned data must itself be serializable
66
+ - The SWC compiler plugin automatically detects and registers classes that implement these symbols
67
+
68
+ <Callout type="warn">
69
+ This method runs inside the workflow context and is subject to the same constraints as `"use workflow"` functions:
70
+ - No Node.js-specific APIs (like `fs`, `path`, `crypto`, etc.)
71
+ - No non-deterministic operations (like `Math.random()` or `Date.now()`)
72
+ - No external network calls
73
+
74
+ Keep this method simple and focused on extracting data from the instance.
75
+ </Callout>
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: Changelog
3
+ description: Latest updates and new features in Workflow DevKit.
4
+ type: overview
5
+ ---
6
+
7
+ # Changelog
8
+
9
+ Stay up to date with the latest changes to Workflow DevKit.
10
+
11
+ ---
12
+
13
+ ## 2026
14
+
15
+ - TBD
@@ -0,0 +1,5 @@
1
+ {
2
+ "title": "Changelog",
3
+ "pages": ["index", "eager-processing"],
4
+ "defaultOpen": false
5
+ }
@@ -180,11 +180,31 @@ interface Streamer {
180
180
  ): Promise<ReadableStream<Uint8Array>>;
181
181
 
182
182
  listStreamsByRunId(runId: string): Promise<string[]>;
183
+
184
+ /** Paginated snapshot of stream chunks. */
185
+ getStreamChunks(
186
+ name: string,
187
+ runId: string,
188
+ options?: { limit?: number; cursor?: string }
189
+ ): Promise<{
190
+ data: { index: number; data: Uint8Array }[];
191
+ cursor: string | null;
192
+ hasMore: boolean;
193
+ done: boolean;
194
+ }>;
195
+
196
+ /** Lightweight metadata: tail index and completion flag. */
197
+ getStreamInfo(
198
+ name: string,
199
+ runId: string
200
+ ): Promise<{ tailIndex: number; done: boolean }>;
183
201
  }
184
202
  ```
185
203
 
186
204
  Streams are identified by a combination of `runId` and `name`. Each workflow run can have multiple named streams.
187
205
 
206
+ `getStreamChunks` returns a paginated snapshot of currently available chunks (unlike `readFromStream` which returns a live `ReadableStream` that waits for new chunks). `getStreamInfo` returns the tail index (last chunk index, 0-based, or `-1` when empty) and whether the stream is complete — useful for resolving negative `startIndex` values into absolute positions.
207
+
188
208
  ## Reference Implementations
189
209
 
190
210
  Study these implementations for guidance:
@@ -6,6 +6,7 @@ summary: Deploy workflows to Vercel with fully-managed storage, queuing, and aut
6
6
  prerequisites:
7
7
  - /docs/deploying
8
8
  related:
9
+ - /docs/how-it-works/encryption
9
10
  - /docs/deploying/world/local-world
10
11
  - /docs/deploying/world/postgres-world
11
12
  ---
@@ -125,7 +126,7 @@ This ensures long-running workflows complete reliably without being affected by
125
126
 
126
127
  The Vercel World uses Vercel's infrastructure for workflow execution:
127
128
 
128
- - **Storage** - Workflow data is stored in Vercel's cloud with automatic replication and encryption
129
+ - **Storage** - Workflow data is stored in Vercel's cloud with automatic replication and [end-to-end encryption](/docs/how-it-works/encryption)
129
130
  - **Queuing** - Steps are distributed across serverless functions with automatic retries
130
131
  - **Authentication** - OIDC tokens provide secure, automatic authentication
131
132
 
@@ -46,6 +46,8 @@ export async function processPayment() {
46
46
  **Solution:** Use unique tokens that include the run ID or other unique identifiers.
47
47
 
48
48
  ```typescript lineNumbers
49
+ import { createHook } from "workflow";
50
+
49
51
  export async function processPayment(orderId: string) {
50
52
  "use workflow";
51
53
 
@@ -60,6 +62,8 @@ export async function processPayment(orderId: string) {
60
62
  The safest approach is to let the Workflow runtime generate a unique token automatically:
61
63
 
62
64
  ```typescript lineNumbers
65
+ import { createHook } from "workflow";
66
+
63
67
  export async function processPayment() {
64
68
  "use workflow";
65
69
 
@@ -71,10 +75,11 @@ export async function processPayment() {
71
75
 
72
76
  ## Handling Hook Conflicts in Your Workflow
73
77
 
74
- When a hook conflict occurs, awaiting the hook will throw a `WorkflowRuntimeError`. You can catch this error to handle the conflict gracefully:
78
+ When a hook conflict occurs, awaiting the hook will throw a `HookConflictError`. You can catch this error to handle the conflict gracefully:
75
79
 
76
80
  ```typescript lineNumbers
77
- import { WorkflowRuntimeError } from "@workflow/errors";
81
+ import { createHook } from "workflow";
82
+ import { HookConflictError } from "@workflow/errors";
78
83
 
79
84
  export async function processPayment(orderId: string) {
80
85
  "use workflow";
@@ -85,8 +90,9 @@ export async function processPayment(orderId: string) {
85
90
  const payment = await hook; // [!code highlight]
86
91
  return { success: true, payment };
87
92
  } catch (error) {
88
- if (error instanceof WorkflowRuntimeError && error.message.includes("hook-conflict")) { // [!code highlight]
93
+ if (HookConflictError.is(error)) { // [!code highlight]
89
94
  // Another workflow is already processing this order
95
+ console.log(`Conflicting token: ${error.token}`);
90
96
  return { success: false, reason: "duplicate-processing" };
91
97
  }
92
98
  throw error; // Re-throw other errors
@@ -37,6 +37,12 @@ Fix common mistakes when creating and executing workflows in the **Workflow DevK
37
37
  <Card href="/docs/errors/corrupted-event-log" title="corrupted-event-log">
38
38
  Learn how to handle corrupted or invalid event logs.
39
39
  </Card>
40
+ <Card href="/docs/errors/step-not-registered" title="step-not-registered">
41
+ Resolve step not registered errors caused by deployment mismatches.
42
+ </Card>
43
+ <Card href="/docs/errors/workflow-not-registered" title="workflow-not-registered">
44
+ Resolve workflow not registered errors caused by deployment mismatches.
45
+ </Card>
40
46
  </Cards>
41
47
 
42
48
  ## Learn More
@@ -0,0 +1,66 @@
1
+ ---
2
+ title: step-not-registered
3
+ description: A step function is not registered in the current deployment.
4
+ type: troubleshooting
5
+ summary: Resolve step not registered errors caused by build issues.
6
+ prerequisites:
7
+ - /docs/foundations/steps
8
+ related:
9
+ - /docs/errors/workflow-not-registered
10
+ - /docs/api-reference/workflow-errors/step-not-registered-error
11
+ ---
12
+
13
+ This error occurs when the Workflow runtime tries to execute a step function that is not registered in the current deployment. When this happens, the step fails (like a `FatalError`) and control is passed back to the workflow function, which can optionally handle the failure.
14
+
15
+ ## Error Message
16
+
17
+ ```
18
+ Step "<stepName>" is not registered in the current deployment.
19
+ This usually indicates a build or bundling issue that caused the step
20
+ to not be included in the deployment.
21
+ ```
22
+
23
+ ## Why This Happens
24
+
25
+ Workflow runs are pegged to a specific deployment, so this error is not caused by newer deployments overriding the running code. Instead, it means the step function was not included in the deployment's workflow bundle at build time.
26
+
27
+ This is an **infrastructure error**, not a user code error.
28
+
29
+ ## Common Causes
30
+
31
+ ### Build tooling issue
32
+
33
+ Something went wrong during the build process that caused the step function to not be included in the workflow bundle. Check your build logs for errors related to workflow bundling. Common issues include:
34
+
35
+ - The step file is missing a valid `"use step"` directive
36
+ - The step function is not exported from the workflow file
37
+ - An esbuild or SWC plugin error silently excluded the step
38
+
39
+ ### Step removed from the codebase
40
+
41
+ The step function was deleted or its `"use step"` directive was removed, but the workflow still references it. Ensure all steps referenced by your workflow are present in the codebase.
42
+
43
+ ## How to Resolve
44
+
45
+ 1. **Check your build logs:** Look for errors or warnings related to workflow bundling. Ensure the step file contains a valid `"use step"` directive and is properly exported.
46
+
47
+ 2. **Verify the step exists:** Confirm the step function is present in the workflow file and has the `"use step"` directive.
48
+
49
+ 3. **Handle it in your workflow:** Since the step fails like a `FatalError`, you can catch it in your workflow code:
50
+
51
+ ```typescript lineNumbers
52
+ declare function processPayment(orderId: string): Promise<any>; // @setup
53
+
54
+ export async function myWorkflow() {
55
+ "use workflow";
56
+
57
+ try {
58
+ const result = await processPayment("order-123");
59
+ return { success: true, result };
60
+ } catch (error) {
61
+ // Step failure (including not registered) is caught here
62
+ console.error("Step failed:", error);
63
+ return { success: false, error: String(error) };
64
+ }
65
+ }
66
+ ```
@@ -43,6 +43,8 @@ export async function webhookWorkflow() {
43
43
  **Solution:** Use `"manual"` or provide a `Response` object.
44
44
 
45
45
  ```typescript lineNumbers
46
+ import { createWebhook } from "workflow";
47
+
46
48
  // Fixed - use "manual"
47
49
  export async function webhookWorkflow() {
48
50
  "use workflow";
@@ -74,6 +76,8 @@ export async function webhookWorkflow() {
74
76
  **Solution:** Create a proper `Response` object.
75
77
 
76
78
  ```typescript lineNumbers
79
+ import { createWebhook } from "workflow";
80
+
77
81
  // Fixed - use Response constructor
78
82
  export async function webhookWorkflow() {
79
83
  "use workflow";
@@ -89,6 +93,8 @@ export async function webhookWorkflow() {
89
93
  ### Default Behavior (202 Response)
90
94
 
91
95
  ```typescript lineNumbers
96
+ import { createWebhook } from "workflow";
97
+
92
98
  // Returns 202 Accepted automatically
93
99
  const webhook = await createWebhook();
94
100
  const request = await webhook;
@@ -98,6 +104,8 @@ const request = await webhook;
98
104
  ### Manual Response
99
105
 
100
106
  ```typescript lineNumbers
107
+ import { createWebhook } from "workflow";
108
+
101
109
  // Manual response control
102
110
  const webhook = await createWebhook({
103
111
  respondWith: "manual",
@@ -120,6 +128,8 @@ await request.respondWith(
120
128
  ### Pre-defined Response
121
129
 
122
130
  ```typescript lineNumbers
131
+ import { createWebhook } from "workflow";
132
+
123
133
  // Immediate response
124
134
  const webhook = await createWebhook({
125
135
  respondWith: new Response("Request received", { status: 200 }),
@@ -49,6 +49,8 @@ export async function webhookWorkflow() {
49
49
  **Solution:** Always call `request.respondWith()` when using manual response mode.
50
50
 
51
51
  ```typescript lineNumbers
52
+ import { createWebhook } from "workflow";
53
+
52
54
  // Fixed - response sent
53
55
  export async function webhookWorkflow() {
54
56
  "use workflow";
@@ -92,6 +94,8 @@ export async function webhookWorkflow() {
92
94
  **Solution:** Ensure all code paths send a response.
93
95
 
94
96
  ```typescript lineNumbers
97
+ import { createWebhook } from "workflow";
98
+
95
99
  // Fixed - response sent in all branches
96
100
  export async function webhookWorkflow() {
97
101
  "use workflow";
@@ -135,6 +139,8 @@ export async function webhookWorkflow() {
135
139
  **Solution:** Use try-catch to handle errors and send appropriate responses.
136
140
 
137
141
  ```typescript lineNumbers
142
+ import { createWebhook } from "workflow";
143
+
138
144
  // Fixed - error handling with response
139
145
  export async function webhookWorkflow() {
140
146
  "use workflow";
@@ -163,6 +169,8 @@ export async function webhookWorkflow() {
163
169
  If you don't need custom response control, consider using the default response mode which automatically returns a `202 Accepted` response:
164
170
 
165
171
  ```typescript lineNumbers
172
+ import { createWebhook } from "workflow";
173
+
166
174
  // Automatic 202 response - no manual response needed
167
175
  export async function webhookWorkflow() {
168
176
  "use workflow";
@@ -0,0 +1,64 @@
1
+ ---
2
+ title: workflow-not-registered
3
+ description: A workflow function is not registered in the current deployment.
4
+ type: troubleshooting
5
+ summary: Resolve workflow not registered errors caused by deployment targeting or build issues.
6
+ prerequisites:
7
+ - /docs/foundations/starting-workflows
8
+ related:
9
+ - /docs/errors/step-not-registered
10
+ - /docs/api-reference/workflow-errors/workflow-not-registered-error
11
+ ---
12
+
13
+ This error occurs when the Workflow runtime tries to execute a workflow function that is not registered in the current deployment. When this happens, the run fails with a `RUNTIME_ERROR` error code.
14
+
15
+ ## Error Message
16
+
17
+ ```
18
+ Workflow "<workflowName>" is not registered in the current deployment.
19
+ This usually means a run was started against a deployment that does not
20
+ have this workflow, or there was a build/bundling issue.
21
+ ```
22
+
23
+ ## Why This Happens
24
+
25
+ This error means the deployment that received the workflow execution request does not have the specified workflow function in its bundle. This is an **infrastructure error**, not a user code error.
26
+
27
+ ## Common Causes
28
+
29
+ ### Run started against a deployment without the workflow
30
+
31
+ A run was started (or restarted from the dashboard UI) targeting a deployment where the workflow was renamed, moved to a different file, or removed entirely.
32
+
33
+ {/* @skip-typecheck: incomplete code sample */}
34
+ ```typescript lineNumbers title="workflows/order.ts (original)"
35
+ export async function processOrder(orderId: string) {
36
+ "use workflow";
37
+ // workflow logic
38
+ }
39
+ ```
40
+
41
+ {/* @skip-typecheck: incomplete code sample */}
42
+ ```typescript lineNumbers title="workflows/order.ts (current deployment)"
43
+ // Renamed from processOrder to handleOrder
44
+ export async function handleOrder(orderId: string) { // [!code highlight]
45
+ "use workflow";
46
+ // workflow logic
47
+ }
48
+ ```
49
+
50
+ If a new run is started targeting the current deployment using the old name `processOrder`, the runtime will not find it.
51
+
52
+ ### Build tooling issue
53
+
54
+ Something went wrong during the build process that caused the workflow function to not be included in the workflow bundle. Check your build logs for errors related to workflow bundling. Common issues include:
55
+
56
+ - The workflow file is missing a valid `"use workflow"` directive
57
+ - The workflow function is not exported from the workflow file
58
+ - An esbuild or SWC plugin error silently excluded the workflow
59
+
60
+ ## How to Resolve
61
+
62
+ 1. **If the workflow was renamed or moved:** Deploy with the workflow restored to its original name and location, then retry the run. Alternatively, start a new run using the updated workflow name against the current deployment.
63
+
64
+ 2. **If it's a build issue:** Check your build logs for errors related to workflow bundling. Ensure the workflow file contains a valid `"use workflow"` directive and is properly exported.
@@ -252,6 +252,10 @@ export async function processOrder(orderId: string) {
252
252
 
253
253
  With background execution, the parent workflow continues immediately after starting the child. The child workflow runs independently with its own event log and can be monitored separately using the returned `runId`.
254
254
 
255
+ <Callout type="info">
256
+ If you want the child workflow to run on the latest deployment rather than the current one, you can pass [`deploymentId: "latest"`](/docs/api-reference/workflow-api/start#using-deploymentid-latest) in the `start()` options. This is currently a Vercel-specific feature. Be aware that the child workflow's function name, file path, argument types, and return type must remain compatible across deployments — renaming the function or changing its location will change the workflow ID, and modifying expected inputs or outputs can cause serialization failures.
257
+ </Callout>
258
+
255
259
  **Choose direct await when:**
256
260
  - The parent needs the child's result before continuing
257
261
  - You want a single, unified event log
@@ -139,6 +139,35 @@ callApi.maxRetries = 5; // Retry up to 5 times on failure (6 total attempts)
139
139
  step can run up to 4 times total (1 initial attempt + 3 retries).
140
140
  </Callout>
141
141
 
142
+ ## Error Codes
143
+
144
+ When a workflow run fails, the error may include a `code` that classifies the failure. You can access it programmatically via the `Run` class:
145
+
146
+ ```typescript lineNumbers
147
+ import { WorkflowRunFailedError } from "@workflow/errors";
148
+ import { start } from "workflow/api";
149
+
150
+ const run = await start(myWorkflow, [input]);
151
+
152
+ try {
153
+ const result = await run.returnValue;
154
+ } catch (err) {
155
+ if (WorkflowRunFailedError.is(err)) {
156
+ console.log(err.cause.code); // "USER_ERROR", "RUNTIME_ERROR", or undefined
157
+ console.log(err.cause.message); // The error message
158
+ }
159
+ }
160
+ ```
161
+
162
+ | Code | Meaning |
163
+ | --- | --- |
164
+ | `USER_ERROR` | An error thrown in your workflow or step code (including propagated step failures like `FatalError`) |
165
+ | `RUNTIME_ERROR` | An internal runtime error such as a corrupted event log or missing data. If you see this, please [file an issue](https://github.com/vercel/workflow/issues) |
166
+
167
+ <Callout type="info">
168
+ The error code is also available on the run entity via the CLI (`npx workflow inspect runs <runId>`) in the `error.code` field, and as an OTEL span attribute (`workflow.error.code`) for observability.
169
+ </Callout>
170
+
142
171
  ## Rolling Back Failed Steps
143
172
 
144
173
  When a workflow fails partway through, it can leave the system in an inconsistent state.