惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 聂微东
IT之家
IT之家
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Y
Y Combinator Blog
博客园 - 【当耐特】
The Cloudflare Blog
宝玉的分享
宝玉的分享
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
Visual Studio Blog
小众软件
小众软件
博客园_首页
Last Week in AI
Last Week in AI
J
Java Code Geeks
V
V2EX
雷峰网
雷峰网
Apple Machine Learning Research
Apple Machine Learning Research
阮一峰的网络日志
阮一峰的网络日志
腾讯CDC
博客园 - 司徒正美
Engineering at Meta
Engineering at Meta
The GitHub Blog
The GitHub Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
MyScale Blog
MyScale Blog
云风的 BLOG
云风的 BLOG
The Register - Security
The Register - Security
M
MIT News - Artificial intelligence
Microsoft Azure Blog
Microsoft Azure Blog
T
The Blog of Author Tim Ferriss
N
Netflix TechBlog - Medium
F
Full Disclosure
B
Blog
H
Help Net Security
C
Check Point Blog
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Jina AI
Jina AI
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
L
LangChain Blog
P
Proofpoint News Feed
D
Docker
Microsoft Security Blog
Microsoft Security Blog

Workflow SDK Documentation

Patterns for Defining Tools Human-in-the-Loop Building Durable AI Agents Queueing User Messages Resumable Streams Sleep, Suspense, and Scheduling Streaming Updates from Tools API Reference Workflow Globals Changelog Resilient run start Cookbook Building a World Deploying Astro Express Fastify Hono Getting Started NestJS Next.js Nitro Nuxt Python SvelteKit Vite corrupted-event-log fetch-in-workflow Errors node-js-module-in-workflow serialization-failed start-invalid-workflow-function step-not-registered timeout-in-workflow webhook-invalid-respond-with-value webhook-response-not-sent workflow-not-registered Errors & Retrying Hooks & Webhooks Idempotency Foundations Serialization Starting Workflows Streaming Versioning Workflows and Steps How the Directives Work Encryption Event Sourcing Framework Integrations Understanding Directives Migration Guides Migrating from AWS Step Functions Migrating from Inngest Migrating from Temporal Observability Testing Server-Based Testing createHook createWebhook defineHook FatalError fetch getStepMetadata getWorkflowMetadata getWritable workflow RetryableError sleep @workflow/vitest DurableAgent @workflow/ai WorkflowChatTransport getHookByToken getRun getWorld workflow/api resumeHook resumeWebhook Chat Session Modeling runtime-decryption-failed Upgrading Workflows abort-signal-timeout-in-workflow Cancellation How Cancellation Works Internal Serializable AbortController and AbortSignal Eager Processing of Steps & Incremental Event Replay TanStack Start Agent Cancellation Sequential & Parallel Execution Workflow Composition Local World | Workflow SDK Postgres World | Workflow SDK Vercel World | Workflow SDK Migrating from trigger.dev Secure Credential Handling Local World | Workflow SDK Postgres World | Workflow SDK Vercel World | Workflow SDK
hook-conflict
2026-05-31 · via Workflow SDK Documentation

Hook tokens must be unique across all running workflows in your project.

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 "<token>" is already in use by another workflow

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

Hardcoded Token Values

// Error - multiple concurrent runs will conflict
export async function processPayment() {
  "use workflow";

  const hook = createHook({ token: "payment-hook" }); 
  // 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.

import { createHook } from "workflow";

export async function processPayment(orderId: string) {
  "use workflow";

  // Include unique identifier in token
  const hook = createHook({ token: `payment-${orderId}` }); 
  const payment = await hook;
}

Omitting the Token (Auto-generated)

The safest approach is to let the Workflow runtime generate a unique token automatically:

import { createHook } from "workflow";

export async function processPayment() {
  "use workflow";

  const hook = createHook(); // Auto-generated unique token
  console.log(`Send webhook to token: ${hook.token}`);
  const payment = await hook;
}

When a hook conflict occurs, awaiting the hook will throw a HookConflictError. The error exposes the token that conflicted and, for current worlds, the run ID that currently owns it. conflictingRunId remains optional for compatibility with older persisted events and world implementations, so guard it before delegating:

import { createHook } from "workflow";
import { HookConflictError } from "@workflow/errors";

export async function processPayment(orderId: string) {
  "use workflow";

  const hook = createHook({ token: `payment-${orderId}` });

  try {
    const payment = await hook; 
    return { success: true, payment };
  } catch (error) {
    if (HookConflictError.is(error)) { 
      // Another workflow is already processing this order
      console.log(`Conflicting token: ${error.token}`);
      if (error.conflictingRunId) {
        console.log(`Active run: ${error.conflictingRunId}`);
      }
      return {
        success: false,
        reason: "duplicate-processing",
        token: error.token,
        runId: error.conflictingRunId
      };
    }
    throw error; // Re-throw other errors
  }
}

This pattern is useful when you want to detect duplicate processing inside the workflow. Runtime APIs such as resumeHook() and getRun() must be called outside workflow functions, for example from an API route or in a step.

Delegate to the Active Run

In idempotency flows, a conflict means another active run already owns the hook token. You can return the duplicate-processing payload from the workflow, resume the active hook to deliver the payload to the existing run, then use getRun(result.runId) to wait for, stream, or cancel the active run:

import { getRun, resumeHook, start } from "workflow/api";
import { processPayment } from "@/workflows/process-payment";

type ProcessPaymentResult =
  | { success: true; payment: unknown }
  | {
      success: false;
      reason: "duplicate-processing";
      token: string;
      runId?: string;
    };

export async function POST(request: Request) {
  const { orderId, payment } = await request.json();
  const run = await start(processPayment, [orderId]);
  const result = (await run.returnValue) as ProcessPaymentResult;

  if (
    result.success === false &&
    result.reason === "duplicate-processing" &&
    result.runId
  ) {
    await resumeHook(result.token, payment); 
    const activeRun = getRun(result.runId); 

    return Response.json({
      delegatedToRunId: activeRun.runId,
      result: await activeRun.returnValue
    });
  }

  return Response.json(result);
}

If the caller needs live output instead of the final result, return activeRun.getReadable() from the same branch. If the duplicate request should replace the active work, call await activeRun.cancel() after inspecting the run.

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
  • Hooks - Learn more about using hooks in workflows
  • getRun - Retrieve or control the active run
  • resumeHook - Deliver data to the active hook
  • createWebhook - Alternative for fixed webhook URLs