paperclipai/paperclip · error
Completion report has no bound task.
Error message
Completion report has no bound task.
What it means
nativeCompletionFeedback loads the heartbeat run for the reported runId and requires it to have a nativeIssueId. When the run row doesn't exist or has no bound native issue, the completion report cannot be attributed to any task and this error is thrown. It is a control-plane invariant: every completion report must map to a native task.
Solutions
- Verify the runId exists in heartbeatRuns and its nativeIssueId column is set before reporting completion.
- Re-create the run through the native flow so it gets a bound nativeIssueId.
- Check you're pointing at the right environment/database (dev vs prod run IDs are not interchangeable).
- If the run row was purged, start a new run instead of reporting against the orphaned ID.
Example fix
// before
await reportCompletion({ runId: cachedRunId, result });
// after
const run = await getRun(cachedRunId);
if (!run?.nativeIssueId) throw new Error(`run ${cachedRunId} is not bound to a task; start a new run`);
await reportCompletion({ runId: cachedRunId, result }); Defensive patterns
Strategy: validation
Validate before calling
const run = await getRun(runId);
if (!run) throw new Error(`run ${runId} not found`);
if (!run.nativeIssueId) throw new Error(`run ${runId} has no bound native task; cannot report completion`); Type guard
const isReportableRun = (r: { id: string; nativeIssueId?: string | null } | undefined): r is { id: string; nativeIssueId: string } => !!r && typeof r.nativeIssueId === "string" && r.nativeIssueId.length > 0; Try / catch
try { await reportCompletion({ runId, result }); } catch (e) { if (e.message === "Completion report has no bound task.") { /* start a new bound run or drop the report */ } else throw e; } Prevention
- Only report completion for runs created through the native-issue flow.
- Never cache run IDs across DB resets or environments.
- Check run.nativeIssueId before queuing completion reports.
When it happens
Trigger: Reporting completion with a runId whose heartbeatRuns row was deleted; a run created outside the native-issue flow (nativeIssueId never set); a typo'd or from-another-environment runId.
Common situations: Agent adapters caching run IDs across DB resets; runs created by older versions before the native binding was introduced; local dev databases wiped while agents still reference old run IDs.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Completion task no longer exists.
- ACPX session is not at a safe suspension point
- Attempt journal is closed
- Cloud runtime identity is already claimed by another…
- codex_run_attach_busy
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/d5e4b21430d64106.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/native-runtime/native-completion-feedback.ts:33
} from "@paperclipai/db";
import {
normalizePrpResultSignals,
type PrpStructuredRunResult,
} from "../../vendor/paperclip-runner/index.js";
/** Read current constraints before accepting the report, not a premature status commit. */
export async function nativeCompletionFeedback(
db: Db,
runId: string,
result: PrpStructuredRunResult,
): Promise<string> {
const run = await db
.select()
.from(heartbeatRuns)
.where(eq(heartbeatRuns.id, runId))
.then((rows) => rows[0]);
if (!run?.nativeIssueId)
throw new Error("Completion report has no bound task.");
const issue = await db
.select()
.from(issues)
.where(
and(
eq(issues.id, run.nativeIssueId),
eq(issues.companyId, run.companyId),
),
)
.then((rows) => rows[0]);
if (!issue) throw new Error("Completion task no longer exists.");
const reviewContext = readNativeReviewAssignmentContext(run.contextSnapshot);
if (reviewContext) {
const review = await getNativeReviewAssignment(db, {
companyId: run.companyId, issueId: issue.id, agentId: run.agentId,
contextSnapshot: reviewContext, allowResolvedByRunId: run.id,
});
if (review?.interaction.status === "pending" && result.reportedWorkDisposition !== "blocked") {View on GitHub (pinned to 3f1d897a7c)