paperclipai/paperclip · error · Error
status must be succeeded, failed, or review_required
Error message
status must be succeeded, failed, or review_required
What it means
Thrown by the record-paperclip-distillation-outcome worker action when params.status is not one of succeeded|failed|review_required. Status drives cursor advancement (only 'succeeded' with cursor/source/window advances the cursor) so an unknown value would leave the cursor in an ambiguous state.
Source
Thrown at packages/plugins/plugin-llm-wiki/src/worker.ts:552
spaceSlug: stringField(params.spaceSlug),
projectId: stringField(params.projectId),
rootIssueId: stringField(params.rootIssueId),
maxCharacters: typeof params.maxCharacters === "number" ? params.maxCharacters : null,
maxCharactersPerSource: typeof params.maxCharactersPerSource === "number" ? params.maxCharactersPerSource : null,
backfillStartAt: stringField(params.backfillStartAt),
backfillEndAt: stringField(params.backfillEndAt),
routineRun: params.routineRun === true,
includeComments: params.includeComments !== false,
includeDocuments: params.includeDocuments !== false,
workItemId: stringField(params.workItemId),
operationIssueId: stringField(params.operationIssueId),
});
});
ctx.actions.register("record-paperclip-distillation-outcome", async (params) => {
const status = stringField(params.status);
if (status !== "succeeded" && status !== "failed" && status !== "review_required") {
throw new Error("status must be succeeded, failed, or review_required");
}
const runId = stringField(params.runId);
if (!runId) throw new Error("runId is required");
return recordPaperclipDistillationOutcome(ctx, {
companyId: readCompanyIdFromParams(params),
wikiId: stringField(params.wikiId),
spaceSlug: stringField(params.spaceSlug),
runId,
cursorId: stringField(params.cursorId),
status,
sourceHash: stringField(params.sourceHash),
sourceWindowEnd: stringField(params.sourceWindowEnd),
warning: stringField(params.warning),
costCents: typeof params.costCents === "number" ? params.costCents : null,
retryCount: typeof params.retryCount === "number" ? params.retryCount : null,
});
});
View on GitHub (pinned to 67001ec6eb)
Solutions
- Map outcomes to exactly: 'succeeded', 'failed', or 'review_required'.
- Normalise upstream enums (e.g. 'success'->'succeeded') before calling the action.
- If a run needs human eyes, use 'review_required', not 'pending'.
Example fix
// before
record(..., { status: 'success', runId });
// after
record(..., { status: 'succeeded', runId }); Defensive patterns
Strategy: type-guard
Validate before calling
const STATUSES = ['succeeded','failed','review_required'] as const;
function assertOutcomeStatus(value: unknown) {
if (typeof value !== 'string' || !(STATUSES as readonly string[]).includes(value)) {
throw new Error(`status must be one of ${STATUSES.join(', ')}`);
}
} Type guard
const OUTCOME_STATUSES = ['succeeded','failed','review_required'] as const;
type DistillationOutcomeStatus = typeof OUTCOME_STATUSES[number];
function isOutcomeStatus(value: unknown): value is DistillationOutcomeStatus {
return typeof value === 'string' && (OUTCOME_STATUSES as readonly string[]).includes(value);
} Prevention
- Map upstream enums ('success'->'succeeded') before calling.
- Use 'review_required' (not 'pending') when a human must look.
When it happens
Trigger: Calling the record-paperclip-distillation-outcome action with status missing, blank, or a value like 'success', 'error', 'pending', 'review'.
Common situations: Caller maps an upstream result enum onto Paperclip status and uses the wrong vocabulary ('success' instead of 'succeeded'); typo; partial params from a retry handler.
Related errors
- Paperclip ingestion fan-out exceeds the hard cap of ${MAX_PA
- Backfill work items must target a projectId or rootIssueId;
- projectId or rootIssueId is required
- runId is required
- projectId or rootIssueId is required
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/08baccff9ace3338.
Report an issue: GitHub.