coleam00/Archon · error

Failed to signal workflow wait: ${err.message}

Error message

Failed to signal workflow wait: ${err.message}

What it means

Thrown by signalWorkflowWait when the database work behind recording an event-wait signal fails. After the event/non-event guard passes, the function runs a conditional UPDATE to atomically record the signal payload in metadata.wait; any driver/SQL failure is logged as `db.workflow_wait_signal_failed` (with runId and event) and rethrown with this message. `{signaled:false}` is returned when the paused row does not match — only an actual DB failure throws.

Source

Thrown at packages/core/src/db/workflows.ts:1701

        await insertWorkflowEvent(query, {
          workflow_run_id: id,
          event_type: 'wait_signaled',
          step_name: workflowWaitStepName(parsedWaitContext),
          data: {
            event: parsedWaitContext.event,
            ...(payload !== undefined ? { payload } : {}),
          },
        });
      }
      return { signaled };
    });
  } catch (error) {
    const err = error as Error;
    getLog().error(
      { err, workflowRunId: id, event: parsedWaitContext.event },
      'db.workflow_wait_signal_failed'
    );
    throw new Error(`Failed to signal workflow wait: ${err.message}`);
  }
}

/**
 * Atomically CLAIM the container write-back apply before the live root is mutated
 * (R2-F4). A conditional UPDATE that sets `metadata.writeback_apply_claimed = true`
 * only while it is unset — so exactly one resume wins the claim. Returns whether
 * THIS caller won. The caller must apply the overlay only on `claimed === true`, and
 * on apply FAILURE release the claim (`releaseWritebackClaim`) so a `workflow resume`
 * can retry; on a crash AFTER a successful apply the claim stays set, so the next
 * resume finds it claimed and does NOT re-apply (no path applies twice).
 */
export async function claimWriteback(id: string): Promise<{ claimed: boolean }> {
  const dialect = getDialect();
  const extract =
    getDatabaseType() === 'postgresql'
      ? "metadata->>'writeback_apply_claimed'"
      : "json_extract(metadata, '$.writeback_apply_claimed')";

View on GitHub (pinned to 0773b97458)

Solutions

  1. Check the `db.workflow_wait_signal_failed` log entry for the underlying driver error
  2. Verify DB connectivity and retry the signal — recording is atomic and safe to re-issue
  3. Confirm metadata.wait JSON on the run row is valid and the configured dialect matches the schema
  4. If signaled:false repeatedly, confirm the run is still status='paused' with the exact wait.event/nodeId

Example fix

// before
await signalWorkflowWait(runId, waitCtx, payload); // throws on DB failure
// after
const { signaled } = await signalWorkflowWait(runId, waitCtx, payload);
if (!signaled) throw new Error(`run ${runId} has no matching paused event wait`);
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm there is a matching paused event wait first
const run = await getWorkflowRun(id);
const wait = run?.metadata?.wait;
const signalable = run?.status === 'paused' && wait?.kind === 'event' && wait.event === waitContext.event;

Type guard

function isSignalableEventRun(run: WorkflowRun | undefined, ctx: Extract<WorkflowWaitContext, { kind: 'event' }>): boolean {
  const w = run?.metadata?.wait;
  return run?.status === 'paused' && w?.kind === 'event' && w.event === ctx.event && w.nodeId === ctx.nodeId;
}

Try / catch

try {
  const { signaled } = await signalWorkflowWait(id, waitContext, payload);
  if (!signaled) log.warn({ id }, 'no matching paused event wait for signal');
} catch (error) {
  log.error({ id, err: error }, 'signal failed at DB layer');
  throw error;
}

Prevention

When it happens

Trigger: Calling signalWorkflowWait for a paused event wait when the connection fails, the metadata UPDATE errors (JSON path invalid for dialect, lock contention, schema mismatch), or payload serialization fails at the driver.

Common situations: Signaling from a webhook handler while the DB is briefly unavailable; corrupted metadata JSON on the run row; mismatched database type configuration breaking the JSON extraction expressions.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/37c775407e76558a. Report an issue: GitHub.