KeygraphHQ/shannon · error · PentestError
Failed to write final report: ${err.message}
Error message
Failed to write final report: ${err.message} What it means
Thrown by assembleFinalReport when fs.ensureDir or fs.writeFile fails while writing the assembled markdown report to <dir>/<ASSEMBLED_REPORT_FILENAME>. The underlying error (ENOSPC, EACCES, EROFS, EMFILE, etc.) is captured in context.originalError. Category 'filesystem', non-retryable. This is a raw OS/filesystem write failure on the final assembled-report artifact.
Source
Thrown at apps/worker/src/services/reporting.ts:86
false,
{ deliverableFile: file.paths, sourceDir },
ErrorCode.DELIVERABLE_NOT_FOUND,
);
}
logger.info(`No ${file.name} deliverable found`);
}
}
const finalContent = sections.join('\n\n');
const finalReportPath = path.join(dir, ASSEMBLED_REPORT_FILENAME);
try {
await fs.ensureDir(dir);
await fs.writeFile(finalReportPath, finalContent);
logger.info(`Final report assembled at ${finalReportPath}`);
} catch (error) {
const err = error as Error;
throw new PentestError(`Failed to write final report: ${err.message}`, 'filesystem', false, {
finalReportPath,
originalError: err.message,
});
}
return finalContent;
}
/**
* Inject model information into the final security report.
* Reads session.json to get the model(s) used, then injects a "Model:" line
* into the Executive Summary section of the report.
*/
export async function injectModelIntoReport(
repoPath: string,
deliverablesSubdir: string | undefined,
outputPath: string,
logger: ActivityLogger,View on GitHub (pinned to 1ae0a142f8)
Solutions
- Read context.originalError and context.finalReportPath on the thrown PentestError to get the OS error code and target path.
- Free disk space on the volume backing the deliverables dir (docker system prune, remove old workspaces).
- Verify the worker container has write permission (correct UID) and the mount is not read-only for the deliverables path.
- Raise the file-descriptor limit (ulimit -n) if EMFILE.
- Re-run the scan or the report activity after fixing the filesystem condition; prior deliverables are preserved so only assembly is retried.
Example fix
// before: deliverables volume full (ENOSPC) // docker run -v repo:/repo ... worker -> 'Failed to write final report: ENOSPC ...' // after: reclaim space and resume // docker system prune -f; rm -rf ./workspaces/<old-workspace> // ./shannon start -u <url> -r <repo> -w <same-workspace>
Defensive patterns
Strategy: try-catch
Validate before calling
// Before report assembly, assert the dir is writable and disk has space
import { df } from 'node:fs/promises'; // pseudo
const dir = deliverablesDir(sourceDir, deliverablesSubdir);
await fs.ensureDir(dir);
const probe = path.join(dir, '.write-probe');
await fs.writeFile(probe, ''); await fs.remove(probe);
// optionally check free space via statfs if available Type guard
function isWriteError(e: unknown): boolean {
return e instanceof Error && /ENOSPC|EACCES|EROFS|EMFILE|ENOSPC/.test(e.message);
} Try / catch
try {
await assembleFinalReport(sourceDir, deliverablesSubdir, logger);
} catch (e) {
if (e instanceof PentestError && /Failed to write final report/.test(e.message)) {
const code = (e.context as any)?.originalError;
if (/ENOSPC/.test(code)) { /* free disk, then retry assembly — deliverables preserved */ }
if (/EACCES|EROFS/.test(code)) { /* fix mount/permissions */ }
}
throw e;
} Prevention
- Monitor disk usage on the volume backing workspaces; prune old workspaces regularly.
- Run the worker container with a UID that has write permission to the deliverables dir.
- Mount the repo read-write, never read-only, for report-capable scans.
- Raise ulimit -n if the scan opens many deliverable files concurrently.
When it happens
Trigger: The worker container's deliverables volume is out of disk space (ENOSPC), the target directory is read-only (EROFS) or lacks write permission (EACCES), the process has exhausted file descriptors (EMFILE), or the path is on a disconnected/unmounted bind mount.
Common situations: Docker volume or overlay filesystem filled by large agent logs/deliverables. The repo path mounted read-only. Container runs as a UID without write permission to the deliverables dir. A full tmpfs backing the workspace.
Related errors
- Cannot create deliverables directory at ${deliverablesDir}
- DELIVERABLE_NOT_FOUND
- CONFIG_NOT_FOUND
- CONFIG_VALIDATION_FAILED
- GIT_CHECKPOINT_FAILED
AI-assisted analysis of KeygraphHQ/shannon@1ae0a142f8 (2026-08-12).
Data as JSON: /api/errors/e408884a41fd0045.
Report an issue: GitHub.