workflow
Version:
Workflow DevKit - Build durable, resilient, and observable workflows
185 lines (136 loc) • 5.14 kB
text/mdx
---
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
---
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
```
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 = await 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
// Fixed - response sent
export async function webhookWorkflow() {
"use workflow";
const webhook = await 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 = await 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
// Fixed - response sent in all branches
export async function webhookWorkflow() {
"use workflow";
const webhook = await 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 = await 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
// Fixed - error handling with response
export async function webhookWorkflow() {
"use workflow";
const webhook = await 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
// Automatic 202 response - no manual response needed
export async function webhookWorkflow() {
"use workflow";
const webhook = await 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)