paperclipai/paperclip · error · WatchdogDecisionApplicationError

creator_run_invalid

creator_run_invalid

Error message

createdByRunId is not valid for this watchdog decision actor

What it means

WatchdogDecisionApplicationError with code creator_run_invalid, raised when a watchdog decision supplies a createdByRunId (or actor.runId) that does not resolve to a run in the same company, or an agent actor claims a creator run owned by a different agent. It validates the actor's authority to act on behalf of the creator run.

Source

Thrown at server/src/modules/active-run-watchdog/application/use-cases.ts:188

      evaluationIssue.originKind !== STALE_ACTIVE_RUN_EVALUATION_ORIGIN_KIND ||
      evaluationIssue.originId !== run.id
    )) {
      throw new WatchdogDecisionApplicationError(
        "evaluation_issue_mismatch",
        "Watchdog decision evaluation issue is not bound to the target run",
      );
    }

    const createdByRunId = input.actor.type === "agent"
      ? input.actor.runId ?? input.createdByRunId ?? null
      : input.actor.type === "board"
        ? input.actor.runId ?? input.createdByRunId ?? null
        : null;
    if (createdByRunId) {
      const creatorRun = await deps.reader.findRunForCompany(input.companyId, createdByRunId);
      const sameAgent = input.actor.type !== "agent" || creatorRun?.agentId === input.actor.agentId;
      if (!creatorRun || !sameAgent) {
        throw new WatchdogDecisionApplicationError(
          "creator_run_invalid",
          "createdByRunId is not valid for this watchdog decision actor",
        );
      }
    }

    const decisionNow = input.now ?? new Date();
    const effectiveSnoozedUntil = input.decision === "snooze"
      ? input.snoozedUntil ?? null
      : input.decision === "continue"
        ? input.snoozedUntil && input.snoozedUntil > decisionNow
          ? input.snoozedUntil
          : new Date(decisionNow.getTime() + deps.continueRearmMs)
        : null;

    return deps.writer.recordDecision(input.companyId, {
      runId: run.id,
      actor: input.actor,

View on GitHub (pinned to 01ad858492)

Solutions

  1. Verify the run exists in the same company via GET for the run before submitting the decision
  2. Ensure actor.runId / createdByRunId refers to a run owned by the acting agent
  3. Omit createdByRunId if there is no valid creator run
  4. Re-fetch fresh run identity after restarts instead of reusing persisted ids

Example fix

// before
recordWatchdogDecision({ companyId, actor: { type: 'agent', agentId }, createdByRunId: staleRunId });
// after
const run = await getRun(companyId, runId);
if (run && run.agentId === agentId) {
  recordWatchdogDecision({ companyId, actor: { type: 'agent', agentId }, createdByRunId: run.id });
}
Defensive patterns

Strategy: validation

Validate before calling

const run = await getRun(companyId, createdByRunId);
if (!run || run.companyId !== companyId || run.agentId !== actor.agentId) throw new Error('invalid creator run');

Type guard

const validCreator = (r, actor) => !!r && r.companyId === actor.companyId && (actor.type !== 'agent' || r.agentId === actor.agentId);

Try / catch

try { await recordWatchdogDecision(input) } catch (e) { if (e.code === 'creator_run_invalid') { /* drop or re-attribute decision */ } else throw e; }

Prevention

When it happens

Trigger: Calling recordWatchdogDecision with createdByRunId of a deleted run, a run from another company, or a run whose agentId differs from actor.agentId for an agent actor.

Common situations: Stale run id cached by an agent after the run was deleted; company id mismatch in multi-tenant calls; agent attempting to attribute decisions to another agent's run.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/90b306c86b2fe4f6. Report an issue: GitHub.