{"record":{"id":"121117a9d422e5de","repo":"paperclipai/paperclip","slug":"pipeline-write-forbidden","errorCode":"pipeline_write_forbidden","errorMessage":"decision.explanation","messagePattern":"decision\\.explanation","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"server/src/routes/pipelines.ts","lineNumber":369,"sourceCode":"}\n\nasync function assertPipelineWriteAccess(\n  req: Request,\n  input: {\n    access: ReturnType<typeof accessService>;\n    companyId: string;\n    pipelineId: string;\n  },\n) {\n  assertPipelineCompanyAccess(req, input.companyId);\n  const decision = await input.access.decide({\n    actor: req.actor,\n    action: \"pipelines:write\",\n    resource: { type: \"company\", companyId: input.companyId },\n    scope: { pipelineId: input.pipelineId },\n  });\n  if (!decision.allowed) {\n    throw new HttpError(403, decision.explanation, {\n      code: decision.code ?? \"pipeline_write_forbidden\",\n      reason: decision.reason,\n      pipelineId: input.pipelineId,\n    });\n  }\n}\n\nfunction mapPipelineDocumentRevision(row: {\n  id: string;\n  companyId: string;\n  documentId: string;\n  pipelineId: string;\n  key: string;\n  revisionNumber: number;\n  title: string | null;\n  format: string;\n  body: string;\n  changeSummary: string | null;","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/routes/pipelines.ts#L351-L387","documentation":"Authorization-denied detail in assertPipelineWriteAccess: the access service's decide() call returned allowed=false for action 'pipelines:write', and decision.explanation is used verbatim as the HttpError 403 message (code from decision.code, defaulting to 'pipeline_write_forbidden'). The message content therefore comes from the access service, not this guard — it names why the actor may not write this pipeline.","triggerScenarios":"Thrown at server/src/routes/pipelines.ts:484 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Provide decision.explanation in the request body as required by this endpoint."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}