KeygraphHQ/shannon · error · Error

Cannot create deliverables directory at ${deliverablesDir}

Error message

Cannot create deliverables directory at ${deliverablesDir}

What it means

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.

Source

Thrown at apps/worker/src/scripts/save-deliverable.ts:87

      args.filePath = next;
      i++;
    }
  }

  return args;
}

// === File Operations ===

function saveDeliverableFile(targetDir: string, filename: string, content: string): string {
  const subdir = process.env.SHANNON_DELIVERABLES_SUBDIR || '.shannon/deliverables';
  const deliverablesDir = join(targetDir, ...subdir.split('/'));
  const filepath = join(deliverablesDir, filename);

  try {
    mkdirSync(deliverablesDir, { recursive: true });
  } catch {
    throw new Error(`Cannot create deliverables directory at ${deliverablesDir}`);
  }

  writeFileSync(filepath, content, 'utf8');
  return filepath;
}

// === Main ===

function main(): void {
  if (process.argv.includes('--help') || process.argv.includes('-h')) {
    printHelp();
    return;
  }

  const args = parseArgs(process.argv);

  // 1. Validate --type
  if (!args.type) {

View on GitHub (pinned to 1ae0a142f8)

Solutions

  1. Ensure the worker process has write permission on targetDir and the resolved subdir (chown/chmod as needed).
  2. If SHANNON_DELIVERABLES_SUBDIR is set, verify it resolves to a writable location inside the mount.
  3. On Linux, run the worker container with a UID matching the repo owner, or chmod the repo to be group-writable.
  4. Retry the workflow - the error is marked retryable and may clear transient FS issues.
  5. Check disk space on the host.

Example fix

# before - worker cannot write to repo
docker run --rm -u 1000:1000 -v "$PWD/repo:/repo" ... save-deliverable ...
# fixes
# (a) match the repo owner's UID:
docker run --rm -u "$(id -u):$(id -g)" -v "$PWD/repo:/repo" ...
# (b) or make the repo group-writable:
chmod -R g+w repo/
# (c) or redirect deliverables to a writable mount:
export SHANNON_DELIVERABLES_SUBDIR="_tmp/deliverables"
Defensive patterns

Strategy: try-catch

Validate before calling

import { access, constants } from 'node:fs';
async function isDirWritable(dir: string): Promise<boolean> {
  try {
    await access(dir, constants.W_OK);
    return true;
  } catch {
    return false;
  }
}

Try / catch

try {
  const filepath = saveDeliverableFile(targetDir, filename, content);
} catch (e) {
  if (e instanceof Error && /Cannot create deliverables directory/.test(e.message)) {
    // log retryable FS error, surface to Temporal for retry, or chmod/remount
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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'.

Related errors


AI-assisted analysis of KeygraphHQ/shannon@1ae0a142f8 (2026-08-12). Data as JSON: /api/errors/c73e20a3664ee95d. Report an issue: GitHub.