paperclipai/paperclip · error · Error
projectId or rootIssueId is required
Error message
projectId or rootIssueId is required
What it means
Thrown by the backfill-paperclip-distillation worker action when neither params.projectId nor params.rootIssueId is provided. This is the action-layer mirror of error 501; backfill must be scoped. The guard fires before createPaperclipDistillationWorkItem is called.
Source
Thrown at packages/plugins/plugin-llm-wiki/src/worker.ts:641
});
return { status: "queued", workItem, operation };
});
ctx.actions.register("enable-paperclip-distillation-active-projects", async (params) => {
return enableActiveProjectDistillation(ctx, {
companyId: readCompanyIdFromParams(params),
wikiId: stringField(params.wikiId),
spaceSlug: stringField(params.spaceSlug),
limit: typeof params.limit === "number" ? params.limit : null,
});
});
ctx.actions.register("backfill-paperclip-distillation", async (params) => {
const companyId = readCompanyIdFromParams(params);
const spaceSlug = stringField(params.spaceSlug);
const projectId = stringField(params.projectId);
const rootIssueId = stringField(params.rootIssueId);
if (!projectId && !rootIssueId) throw new Error("projectId or rootIssueId is required");
const backfillStartAt = stringField(params.backfillStartAt);
const backfillEndAt = stringField(params.backfillEndAt);
const idempotencyScope = rootIssueId ? `root:${rootIssueId}` : `project:${projectId}`;
const workItem = await createPaperclipDistillationWorkItem(ctx, {
companyId,
wikiId: stringField(params.wikiId),
spaceSlug,
kind: "backfill",
projectId,
rootIssueId,
requestedByIssueId: stringField(params.requestedByIssueId),
priority: "low",
idempotencyKey: stringField(params.idempotencyKey) ?? `backfill:${idempotencyScope}:${backfillStartAt ?? "begin"}:${backfillEndAt ?? "now"}`,
metadata: { backfillStartAt, backfillEndAt, requestedFrom: "backfill-paperclip-distillation" },
});
const operation = await createOperationIssue(ctx, {
companyId,
wikiId: stringField(params.wikiId),View on GitHub (pinned to 67001ec6eb)
Solutions
- Pass projectId or rootIssueId on the backfill action.
- For company-wide coverage, loop over projects and call the action once per projectId.
- Use camelCase param names (projectId, rootIssueId).
Example fix
// before
ctx.actions.run('backfill-paperclip-distillation', { companyId });
// after
ctx.actions.run('backfill-paperclip-distillation', { companyId, projectId }); Defensive patterns
Strategy: validation
Validate before calling
function assertBackfillScope(params: { projectId?: string | null; rootIssueId?: string | null }) {
if (!params.projectId && !params.rootIssueId) throw new Error('projectId or rootIssueId is required');
} Type guard
function hasBackfillScope(p: unknown): p is { projectId: string } | { rootIssueId: string } {
return !!p && typeof p === 'object' && (!!(p as any).projectId || !!(p as any).rootIssueId);
} Try / catch
try { await worker.actions['backfill-paperclip-distillation'](params); } catch (err) { if (/projectId or rootIssueId is required/.test(String(err))) { /* loop projects */ } else throw err; } Prevention
- Loop over projects for company-wide backfill.
- Use camelCase param keys (projectId, rootIssueId).
When it happens
Trigger: Invoking the backfill-paperclip-distillation action with projectId and rootIssueId both null/blank.
Common situations: Operator requests a company-wide backfill; script enumerates companies but not projects; projectId was passed as 'project_id'.
Related errors
- Backfill work items must target a projectId or rootIssueId;
- 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/effa43e2f53cb501.
Report an issue: GitHub.