{"record":{"id":"cedcf9b03c4b2fdf","repo":"paperclipai/paperclip","slug":"decision-message","errorCode":null,"errorMessage":"${decision.message}","messagePattern":"\\$\\{decision\\.message\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/plugin-llm-wiki/src/wiki/core.ts","lineNumber":475,"sourceCode":"async function requirePaperclipIngestionPolicy(\n  ctx: PluginContext,\n  input: { companyId: string; wikiId: string; spaceSlug?: string | null },\n  purpose: PaperclipIngestionPolicyPurpose,\n  options: { requireEnabledProfile?: boolean } = {},\n): Promise<WikiSpace> {\n  const space = await resolveSpace(ctx, {\n    companyId: input.companyId,\n    wikiId: input.wikiId,\n    spaceSlug: input.spaceSlug,\n  });\n  const profile = await profileForSpace(ctx, input.companyId, space);\n  const decision = evaluatePaperclipProfilePolicy({\n    space,\n    profile,\n    purpose,\n    requireEnabledProfile: options.requireEnabledProfile,\n  });\n  if (!decision.allowed) throw new Error(decision.message);\n  return decision.space;\n}\n\nfunction assertPaperclipSourceScopePayload(input: { projectId?: string | null; rootIssueId?: string | null }) {\n  if (input.projectId && input.rootIssueId) {\n    throw new Error(\"Paperclip source scope must specify either projectId or rootIssueId, not both.\");\n  }\n}\n\nfunction assertRequestedCharacterLimit(name: string, value: unknown, max: number) {\n  if (value == null) return;\n  if (typeof value !== \"number\" || !Number.isFinite(value) || value < 1) {\n    throw new Error(`${name} must be a positive number.`);\n  }\n  if (Math.floor(value) > max) {\n    throw new Error(`${name} exceeds the hard Paperclip ingestion cap of ${max} characters.`);\n  }\n}","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/plugin-llm-wiki/src/wiki/core.ts#L457-L493","documentation":"Thrown by requirePaperclipIngestionPolicy() when evaluatePaperclipProfilePolicy() returns allowed=false. The message is the decision's own message, which can be one of: archived_space (space.status !== \"active\"), restricted_space (space.accessScope !== \"shared\"), profile_disabled (non-default space, requireEnabledProfile set, profile not enabled), or profile_empty (profile enabled but sourceScopes empty). The purpose (e.g. ingest, profile_update) is interpolated into each.","triggerScenarios":"Attempting ingestion against an archived space. Against a non-shared (private) space. Against a non-default space whose profile is disabled or has no source scopes, when requireEnabledProfile is set.","commonSituations":"Trying to ingest Paperclip sources into a custom (non-default) wiki space before configuring an enabled profile with at least one source scope. Ingestion attempted after a space was archived. Access scope restricted to private before host permissions were wired.","solutions":["Read the decision.message — it names the specific reason; address that reason (un-archive the space, switch accessScope to shared, enable the profile, or add a source scope).","If you do not need a custom space, ingest against the default space (slug \"default\") where the profile gate does not apply.","Call getPaperclipIngestionProfile() first to inspect policyBlocks and effectiveState before attempting the operation."],"exampleFix":"// before\nawait requirePaperclipIngestionPolicy(ctx, { companyId, wikiId, spaceSlug: \"my-team\" }, \"ingest\", { requireEnabledProfile: true });\n// after\n// ensure profile is enabled with >=1 source scope, then:\nawait requirePaperclipIngestionPolicy(ctx, { companyId, wikiId, spaceSlug: \"my-team\" }, \"ingest\", { requireEnabledProfile: true });","handlingStrategy":"validation","validationCode":"const profile = await getPaperclipIngestionProfile(ctx, { companyId, wikiId, spaceSlug });\nif (profile.effectiveState === \"policy_blocked\") {\n  throw new Error(`Cannot ingest: ${profile.policyBlocks.join(\"; \")}`);\n}","typeGuard":"function isPolicyAllowed(d: { allowed: boolean }): d is { allowed: true } {\n  return d.allowed === true;\n}","tryCatchPattern":"try {\n  await requirePaperclipIngestionPolicy(ctx, input, purpose, opts);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Paperclip ingestion policy denied\")) {\n    // read reason from message, fix space/profile, then retry or surface\n  } else throw err;\n}","preventionTips":["Inspect getPaperclipIngestionProfile().policyBlocks before ingesting.","Configure an enabled profile with >=1 scope on custom spaces.","Ingest against the default space to bypass the profile gate."],"tags":["llm-wiki","policy","ingest","paperclip"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}