workflow
Version:
Workflow DevKit - Build durable, resilient, and observable workflows
120 lines (86 loc) • 4.13 kB
text/mdx
---
title: hook-conflict
description: Hook tokens must be unique across all running workflows in your project.
type: troubleshooting
summary: Resolve hook token conflicts by using unique or auto-generated tokens.
prerequisites:
- /docs/foundations/hooks
related:
- /docs/api-reference/workflow/create-hook
- /docs/api-reference/workflow/define-hook
---
This error occurs when you try to create a hook with a token that is already in use by another active workflow run. Hook tokens must be unique across all running workflows in your project.
```
Hook token conflict: Hook with token <token> already exists for this project
```
Hooks use tokens to identify incoming webhook payloads. When you create a hook with `createHook({ token: "my-token" })`, the Workflow runtime reserves that token for your workflow run. If another workflow run is already using that token, a conflict occurs.
This typically happens when:
1. **Two workflows start simultaneously** with the same hardcoded token
2. **A previous workflow run is still waiting** for a hook when a new run tries to use the same token
{/* @skip-typecheck: incomplete code sample */}
```typescript lineNumbers
// Error - multiple concurrent runs will conflict
export async function processPayment() {
"use workflow";
const hook = createHook({ token: "payment-hook" }); // [!code highlight]
// If another run is already waiting on "payment-hook", this will fail
const payment = await hook;
}
```
**Solution:** Use unique tokens that include the run ID or other unique identifiers.
```typescript lineNumbers
export async function processPayment(orderId: string) {
"use workflow";
// Include unique identifier in token
const hook = createHook({ token: `payment-${orderId}` }); // [!code highlight]
const payment = await hook;
}
```
The safest approach is to let the Workflow runtime generate a unique token automatically:
```typescript lineNumbers
export async function processPayment() {
"use workflow";
const hook = createHook(); // Auto-generated unique token // [!code highlight]
console.log(`Send webhook to token: ${hook.token}`);
const payment = await hook;
}
```
When a hook conflict occurs, awaiting the hook will throw a `WorkflowRuntimeError`. You can catch this error to handle the conflict gracefully:
```typescript lineNumbers
import { WorkflowRuntimeError } from "@workflow/errors";
export async function processPayment(orderId: string) {
"use workflow";
const hook = createHook({ token: `payment-${orderId}` });
try {
const payment = await hook; // [!code highlight]
return { success: true, payment };
} catch (error) {
if (error instanceof WorkflowRuntimeError && error.message.includes("hook-conflict")) { // [!code highlight]
// Another workflow is already processing this order
return { success: false, reason: "duplicate-processing" };
}
throw error; // Re-throw other errors
}
}
```
This pattern is useful when you want to detect and handle duplicate processing attempts instead of letting the workflow fail.
Hook tokens are automatically released when:
- The workflow run **completes** (successfully or with an error)
- The workflow run is **cancelled**
- The hook is explicitly **disposed**
After a workflow completes, its hook tokens become available for reuse by other workflows.
1. **Use auto-generated tokens** when possible - they are guaranteed to be unique
2. **Include unique identifiers** if you need custom tokens (order ID, user ID, etc.)
3. **Avoid reusing the same token** across multiple concurrent workflow runs
4. **Consider using webhooks** (`createWebhook`) if you need a fixed, predictable URL that can receive multiple payloads
## Related
- [Hooks](/docs/foundations/hooks) - Learn more about using hooks in workflows
- [createWebhook](/docs/api-reference/workflow/create-webhook) - Alternative for fixed webhook URLs