paperclipai/paperclip · error · Error
Backfill work items must target a projectId or rootIssueId;
Error message
Backfill work items must target a projectId or rootIssueId; whole-company backfill is not allowed.
What it means
Thrown by createPaperclipDistillationWorkItem when kind === 'backfill' but the resolved scope has neither projectId nor rootIssueId. Backfill must target a single project or root-issue subtree; whole-company backfill is intentionally disallowed to keep distillation cost and cursor advancement bounded. The scope is derived by paperclipCursorScopeMetadata(input).
Source
Thrown at packages/plugins/plugin-llm-wiki/src/wiki/core.ts:2904
AND id = $6`,
[input.companyId, wikiId, input.runId, input.sourceWindowEnd, input.sourceHash, input.cursorId, space.id],
);
}
return {
status: input.status,
cursorAdvanced: input.status === "succeeded" && Boolean(input.cursorId && input.sourceHash && input.sourceWindowEnd),
};
}
export async function createPaperclipDistillationWorkItem(ctx: PluginContext, input: PaperclipDistillationWorkItemInput) {
const wikiId = normalizeWikiId(input.wikiId);
assertPaperclipSourceScopePayload(input);
const space = await requirePaperclipIngestionPolicy(ctx, { companyId: input.companyId, wikiId, spaceSlug: input.spaceSlug }, "queue", { requireEnabledProfile: true });
const itemId = randomUUID();
const scope = paperclipCursorScopeMetadata(input);
if (input.kind === "backfill" && !scope.projectId && !scope.rootIssueId) {
throw new Error("Backfill work items must target a projectId or rootIssueId; whole-company backfill is not allowed.");
}
await ctx.db.execute(
`INSERT INTO ${distillationWorkItemTable(ctx)} AS paperclip_distillation_work_items
(id, company_id, wiki_id, space_id, work_item_kind, status, priority, project_id, root_issue_id, requested_by_issue_id, idempotency_key, metadata)
VALUES ($1, $2, $3, $11, $4, 'pending', $5, $6, $7, $8, $9, $10::jsonb)
ON CONFLICT (company_id, wiki_id, space_id, idempotency_key)
DO UPDATE SET priority = EXCLUDED.priority,
metadata = paperclip_distillation_work_items.metadata || EXCLUDED.metadata,
updated_at = now()`,
[
itemId,
input.companyId,
wikiId,
input.kind,
input.priority ?? "medium",
scope.projectId,
scope.rootIssueId,
input.requestedByIssueId ?? null,View on GitHub (pinned to 67001ec6eb)
Solutions
- Provide exactly one of projectId or rootIssueId on the backfill request.
- If you need company-wide coverage, enumerate projects via ctx.projects.list and submit one backfill work item per projectId.
- For issue-tree backfill, pass rootIssueId of the top-level issue, not a leaf issue id.
Example fix
// before
createPaperclipDistillationWorkItem(ctx, { companyId, kind: 'backfill' });
// after
createPaperclipDistillationWorkItem(ctx, { companyId, kind: 'backfill', projectId }); Defensive patterns
Strategy: validation
Validate before calling
function assertBackfillScope(input: { projectId?: string | null; rootIssueId?: string | null }) {
if (!input.projectId && !input.rootIssueId) {
throw new Error('Backfill requires projectId or rootIssueId');
}
} Type guard
function hasBackfillScope(input: unknown): input is { projectId: string } | { rootIssueId: string } {
return !!input && typeof input === 'object' && (
(typeof (input as any).projectId === 'string' && (input as any).projectId.length > 0) ||
(typeof (input as any).rootIssueId === 'string' && (input as any).rootIssueId.length > 0)
);
} Try / catch
try {
await createPaperclipDistillationWorkItem(ctx, { companyId, kind: 'backfill', projectId, rootIssueId });
} catch (err) {
if (err instanceof Error && /whole-company backfill/.test(err.message)) {
// enumerate projects and submit one backfill each
} else throw err;
} Prevention
- Always scope backfill to a project or root issue.
- Validate scope presence at the worker action layer before calling the core function.
When it happens
Trigger: Calling createPaperclipDistillationWorkItem with kind:'backfill' while leaving projectId and rootIssueId null/empty, e.g. via the backfill-paperclip-distillation worker action without those params.
Common situations: Operator tries to 'backfill everything' after enabling distillation for a company; a script iterates companies but forgets to scope per project; rootIssueId was passed under the wrong param key.
Related errors
- projectId or rootIssueId is required
- Paperclip ingestion fan-out exceeds the hard cap of ${MAX_PA
- projectId or rootIssueId is required
- status must be succeeded, failed, or review_required
- runId is required
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/0889bb4ea59d83f1.
Report an issue: GitHub.