paperclipai/paperclip · error · Error
: capture has no states
Error message
${app.slug}: capture has no states What it means
After parsing, each app whose slug has a parsed capture must have at least one state. Because parseCapture() only returns entries derived from '## State:' headings, an empty array here means the capture matched the 99-count check but still yielded no states for this app — an inconsistency caught before writing output files.
Solutions
- Inspect the capture file for the app's slug and ensure at least one '## State:' section survives parsing.
- Check recent changes to parseCapture() for filtering logic that can drop all states; fix the filter or re-add the states.
- If the app should not have a capture at all, remove the capture file (and adjust the 99-count) rather than shipping an empty capture.
Example fix
// before
const states = stateMatches.filter((m) => wantState(m[1])); // can be []
// after
if (states.length === 0) throw new Error(`${fileName}: no captured states`); Defensive patterns
Strategy: validation
Validate before calling
for (const app of apps) {
const cap = parsedCaptures[app.slug];
if (cap && cap.length === 0) throw new Error(`${app.slug}: capture parsed to zero states`);
} Prevention
- Keep parseCapture() fail-fast (throw on zero headings) rather than returning [].
- Review any new state-filtering logic in parseCapture for empty-result edge cases.
- Add a unit test that every parsed capture yields >= 1 state.
When it happens
Trigger: In the final loop over apps, for an app where parsedCaptures[app.slug] exists (the capture file <slug>.md was parsed) and its array length is 0. In practice parseCapture throws on zero headings, so this guards against a future parseCapture change returning an empty array (e.g. filtering states) or an empty-array assignment.
Common situations: Refactoring parseCapture to filter/skip states and returning [] for edge-case files; test doubles or patched ingestion code injecting an empty capture list; a slug whose capture file exists but whose states are all filtered out by a new criterion.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- / / : required field needs placeholder
- / : oauth requires ownershipModes
- / : tool api_key requires keyPlacement
- : invalid AppDefinition
- Expected 99 captures, found
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/c86ff84896b1c182.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/ingest-app-definitions.mjs:1644
providers: captureFiles.map((fileName) => {
const slug = path.basename(fileName, ".md");
const states = parsedCaptures[slug].map((state) => inferState(slug, state));
return {
slug,
stateCount: states.length,
states,
ambiguities: states
.filter((state) => !state.auth)
.map(
(state) => `Auth is not explicit in capture state: ${state.label}`,
),
};
}),
};
for (const app of apps) {
validateApp(app);
if (parsedCaptures[app.slug] && parsedCaptures[app.slug].length === 0)
throw new Error(`${app.slug}: capture has no states`);
}
fs.mkdirSync(out, { recursive: true });
for (const app of apps)
fs.writeFileSync(
path.join(out, `${app.slug}.json`),
JSON.stringify(app, null, 2) + "\n",
);
if (!definitionsOnly) fs.writeFileSync(
path.join(root, "packages/shared/src/app-definitions.ingestion-report.json"),
JSON.stringify(reviewReport, null, 2) + "\n",
);
const imports = apps
.map(
(a, i) =>
`import a${i} from "./app-definitions/${a.slug}.json" with { type: "json" };`,
)
.join("\n");
fs.writeFileSync(View on GitHub (pinned to 3f1d897a7c)