{"record":{"id":"c73e20a3664ee95d","repo":"KeygraphHQ/shannon","slug":"cannot-create-deliverables-directory-at-delivera","errorCode":null,"errorMessage":"Cannot create deliverables directory at ${deliverablesDir}","messagePattern":"Cannot create deliverables directory at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/worker/src/scripts/save-deliverable.ts","lineNumber":87,"sourceCode":"      args.filePath = next;\n      i++;\n    }\n  }\n\n  return args;\n}\n\n// === File Operations ===\n\nfunction saveDeliverableFile(targetDir: string, filename: string, content: string): string {\n  const subdir = process.env.SHANNON_DELIVERABLES_SUBDIR || '.shannon/deliverables';\n  const deliverablesDir = join(targetDir, ...subdir.split('/'));\n  const filepath = join(deliverablesDir, filename);\n\n  try {\n    mkdirSync(deliverablesDir, { recursive: true });\n  } catch {\n    throw new Error(`Cannot create deliverables directory at ${deliverablesDir}`);\n  }\n\n  writeFileSync(filepath, content, 'utf8');\n  return filepath;\n}\n\n// === Main ===\n\nfunction main(): void {\n  if (process.argv.includes('--help') || process.argv.includes('-h')) {\n    printHelp();\n    return;\n  }\n\n  const args = parseArgs(process.argv);\n\n  // 1. Validate --type\n  if (!args.type) {","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/KeygraphHQ/shannon/blob/1ae0a142f8525410a688f0309fd003cc5b1d92de/apps/worker/src/scripts/save-deliverable.ts#L69-L105","documentation":"Thrown by saveDeliverableFile in save-deliverable when mkdirSync(deliverablesDir, { recursive: true }) throws. The target directory is <targetDir>/<SHANNON_DELIVERABLES_SUBDIR or '.shannon/deliverables'>; failure is typically permissions, a read-only mount, or disk full. Surfaced by main() as a JSON error with retryable:true and exit code 1, because filesystem errors are often transient.","triggerScenarios":"save-deliverable runs (worker persists a deliverable) and mkdirSync fails on the resolved deliverables directory - e.g. targetDir is read-only, the path crosses a read-only mount, the process lacks write permission, or the disk is full. SHANNON_DELIVERABLES_SUBDIR can redirect the location.","commonSituations":"Worker container runs as a UID without write access to the mounted repo (Linux permission mismatch); SHANNON_DELIVERABLES_SUBDIR points at a read-only volume; disk-full CI runner; macOS/Windows filesystem case collision on '.shannon'.","solutions":["Ensure the worker process has write permission on targetDir and the resolved subdir (chown/chmod as needed).","If SHANNON_DELIVERABLES_SUBDIR is set, verify it resolves to a writable location inside the mount.","On Linux, run the worker container with a UID matching the repo owner, or chmod the repo to be group-writable.","Retry the workflow - the error is marked retryable and may clear transient FS issues.","Check disk space on the host."],"exampleFix":"# before - worker cannot write to repo\ndocker run --rm -u 1000:1000 -v \"$PWD/repo:/repo\" ... save-deliverable ...\n# fixes\n# (a) match the repo owner's UID:\ndocker run --rm -u \"$(id -u):$(id -g)\" -v \"$PWD/repo:/repo\" ...\n# (b) or make the repo group-writable:\nchmod -R g+w repo/\n# (c) or redirect deliverables to a writable mount:\nexport SHANNON_DELIVERABLES_SUBDIR=\"_tmp/deliverables\"","handlingStrategy":"try-catch","validationCode":"import { access, constants } from 'node:fs';\nasync function isDirWritable(dir: string): Promise<boolean> {\n  try {\n    await access(dir, constants.W_OK);\n    return true;\n  } catch {\n    return false;\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const filepath = saveDeliverableFile(targetDir, filename, content);\n} catch (e) {\n  if (e instanceof Error && /Cannot create deliverables directory/.test(e.message)) {\n    // log retryable FS error, surface to Temporal for retry, or chmod/remount\n  } else throw e;\n}","preventionTips":["Run the worker container with a UID matching the repo owner (or group-writable repo).","Verify SHANNON_DELIVERABLES_SUBDIR resolves to a writable location inside the mount.","Check host disk space before launching long scans.","Keep the repo on a writable volume; do not mount it read-only."],"tags":["filesystem","docker","permissions","deliverables","cli"],"backgroundTag":null,"analyzedSha":"1ae0a142f8525410a688f0309fd003cc5b1d92de","analyzedAt":"2026-08-12T17:40:03.583Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}