UNPKG

workflow

Version:

Workflow SDK - Build durable, resilient, and observable workflows

197 lines (143 loc) • 5.96 kB
--- title: webhook-response-not-sent description: Manual webhooks must send a response before execution completes. type: troubleshooting summary: Resolve the webhook-response-not-sent error by ensuring all code paths call respondWith. prerequisites: - /docs/foundations/hooks related: - /docs/api-reference/workflow/create-webhook --- <CopyPrompt text="Fix webhook-response-not-sent errors. Find `createWebhook({ respondWith: &quot;manual&quot; })` usage. In the workflow, await the webhook request and pass the `RequestWithResponse` into a `&quot;use step&quot;` helper for validation and side effects. In every success, validation failure, catch, and early-return branch, call `await request.respondWith(new Response(...))` or `await request.respondWith(Response.json(...))` exactly once before the webhook completes. If manual control is not needed, remove `respondWith: &quot;manual&quot;` or use a static `Response` option. Add tests or local webhook calls for success, invalid input, and thrown-error paths." /> This error occurs when a webhook is configured with `respondWith: "manual"` but the workflow does not send a response using `request.respondWith()` before the webhook execution completes. ## Error message ```text Workflow run did not send a response ``` ## Why this happens When you create a webhook with `respondWith: "manual"`, you are responsible for calling `request.respondWith()` to send the HTTP response back to the caller. If the workflow execution completes without sending a response, this error will be thrown. The webhook infrastructure waits for a response to be sent, and if none is provided, it cannot complete the HTTP request properly. ## Common causes ### Forgetting to call `request.respondWith()` ```typescript lineNumbers // Error - no response sent export async function webhookWorkflow() { "use workflow"; const webhook = createWebhook({ respondWith: "manual", }); const request = await webhook; const data = await request.json(); // Process data... console.log(data); // Error: workflow ends without calling request.respondWith() // [!code highlight] } ``` **Solution:** Always call `request.respondWith()` when using manual response mode. ```typescript lineNumbers import { createWebhook } from "workflow"; // Fixed - response sent export async function webhookWorkflow() { "use workflow"; const webhook = createWebhook({ respondWith: "manual", }); const request = await webhook; const data = await request.json(); // Process data... console.log(data); // Send response before workflow ends // [!code highlight] await request.respondWith(new Response("Processed", { status: 200 })); // [!code highlight] } ``` ### Conditional response logic ```typescript lineNumbers // Error - response only sent in some branches export async function webhookWorkflow() { "use workflow"; const webhook = createWebhook({ respondWith: "manual", }); const request = await webhook; const data = await request.json(); if (data.isValid) { await request.respondWith(new Response("OK", { status: 200 })); } // Error: no response when data.isValid is false // [!code highlight] } ``` **Solution:** Ensure all code paths send a response. ```typescript lineNumbers import { createWebhook } from "workflow"; // Fixed - response sent in all branches export async function webhookWorkflow() { "use workflow"; const webhook = createWebhook({ respondWith: "manual", }); const request = await webhook; const data = await request.json(); if (data.isValid) { // [!code highlight] await request.respondWith(new Response("OK", { status: 200 })); // [!code highlight] } else { // [!code highlight] await request.respondWith(new Response("Invalid data", { status: 400 })); // [!code highlight] } // [!code highlight] } ``` ### Exception before response ```typescript lineNumbers // Error - exception thrown before response export async function webhookWorkflow() { "use workflow"; const webhook = createWebhook({ respondWith: "manual", }); const request = await webhook; // Error occurs here // [!code highlight] throw new Error("Something went wrong"); // [!code highlight] // Never reached await request.respondWith(new Response("OK", { status: 200 })); } ``` **Solution:** Use try-catch to handle errors and send appropriate responses. ```typescript lineNumbers import { createWebhook } from "workflow"; // Fixed - error handling with response export async function webhookWorkflow() { "use workflow"; const webhook = createWebhook({ respondWith: "manual", }); const request = await webhook; try { // [!code highlight] // Process request... const result = await processData(request); // [!code highlight] await request.respondWith(new Response("OK", { status: 200 })); // [!code highlight] } catch (error) { // [!code highlight] // Send error response // [!code highlight] await request.respondWith( // [!code highlight] new Response("Internal error", { status: 500 }) // [!code highlight] ); // [!code highlight] } // [!code highlight] } ``` ## Alternative: Use default response mode If you don't need custom response control, consider using the default response mode which automatically returns a `202 Accepted` response: ```typescript lineNumbers import { createWebhook } from "workflow"; // Automatic 202 response - no manual response needed export async function webhookWorkflow() { "use workflow"; const webhook = createWebhook(); // [!code highlight] const request = await webhook; // Process request asynchronously await processData(request); // No need to call request.respondWith() } ``` ## Learn more - [createWebhook() API Reference](/docs/api-reference/workflow/create-webhook) - [resumeWebhook() API Reference](/docs/api-reference/workflow-api/resume-webhook) - [Webhooks Guide](/docs/foundations/hooks)