paperclipai/paperclip · error · ToolGatewayHttpError
run_company_mismatch
run_company_mismatch
Error message
Run does not belong to company
What it means
Tenant guard on run resolution: the heartbeatRuns row for runId is missing or its companyId differs from the caller's company. Enforces company scoping for run-context lookups; the foreign runId is at fault.
Solutions
- Use a run ID that belongs to the authenticated company; cross-company run access is rejected.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at server/src/services/tool-gateway.ts:1063 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/493696f1888c0038.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/tool-gateway.ts:1485
companyId: string;
agentId: string;
runId: string;
issueId?: string | null;
projectId?: string | null;
}): Promise<{ issueId: string | null; projectId: string | null }> {
const [run] = await db
.select({
companyId: heartbeatRuns.companyId,
agentId: heartbeatRuns.agentId,
status: heartbeatRuns.status,
contextSnapshot: heartbeatRuns.contextSnapshot,
})
.from(heartbeatRuns)
.where(eq(heartbeatRuns.id, input.runId))
.limit(1);
if (!run || run.companyId !== input.companyId) {
throw new ToolGatewayHttpError(
403,
"Run does not belong to company",
"run_company_mismatch",
);
}
if (run.agentId !== input.agentId) {
throw new ToolGatewayHttpError(
403,
"Run does not belong to agent",
"run_agent_mismatch",
);
}
if (!ACTIVE_GATEWAY_RUN_STATUSES.has(run.status)) {
throw new ToolGatewayHttpError(403, "Run is not active", "run_inactive");
}
const snapshot = asRecord(run.contextSnapshot);
const snapshotIssueId = stringValue(snapshot?.issueId);View on GitHub (pinned to 3f1d897a7c)