{"record":{"id":"78e262ecf818177f","repo":"santifer/career-ops","slug":"could-not-save-report-err-message","errorCode":null,"errorMessage":"⚠️   Could not save report: ${err.message}","messagePattern":"⚠️   Could not save report: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gemini-eval.mjs","lineNumber":585,"sourceCode":"      ];\n      // Optional `url` column, appended only when there is a real URL to put in\n      // it. merge-tracker.mjs matches on the URL FIRST -- the one tier that can\n      // prove two same-title rows are different openings -- so writing it here\n      // puts the row on that tier at merge time instead of leaving it to a\n      // later `--backfill-urls`. Label and value are appended together: the\n      // headed path resolves cells by NAME, so a value without its label would\n      // be dropped, and a label without its value would leave the url cell\n      // absent (#3517).\n      const trackerHeader = postingUrl ? `${TSV_ADDITION_HEADER}\\turl` : TSV_ADDITION_HEADER;\n      if (postingUrl) trackerFields.push(tsvSafe(postingUrl));\n      // Header row first: merge-tracker resolves the fields by name, so this\n      // row cannot be ingested into the wrong columns (#3517).\n      writeFileSync(trackerPath, `${trackerHeader}\\n${trackerFields.join('\\t')}\\n`, 'utf-8');\n      console.log(`\\n✅  Report saved: reports/${filename}`);\n      console.log(`📊  Tracker addition saved: batch/tracker-additions/${num}-${companySlug}.tsv`);\n      reportSaved = true;\n    } catch (err) {\n      console.warn(`⚠️   Could not save report: ${err.message}`);\n      process.exitCode = 1;\n    }\n\n    if (reportSaved) {\n      try {\n        const mergeOutput = execFileSync(process.execPath, [join(CODE_ROOT, 'merge-tracker.mjs')], {\n          cwd: CODE_ROOT,\n          encoding: 'utf-8',\n          stdio: ['ignore', 'pipe', 'pipe'],\n          timeout: 30000,\n        });\n        if (mergeOutput.trim()) console.log(mergeOutput.trim());\n        console.log('📊  Tracker merged into data/applications.md.');\n      } catch (err) {\n        console.warn(`⚠️   Report saved, but could not merge tracker addition into data/applications.md: ${err.message}`);\n        process.exitCode = 1;\n      }\n    }","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/gemini-eval.mjs#L567-L603","documentation":"gemini-eval.mjs writes the evaluation report to reports/ and a one-row TSV to batch/tracker-additions/. When writeFileSync (or any sibling write in the try block) fails — bad path, read-only filesystem, ENOSPC, ENOENT parent directory — the tool warns, sets process.exitCode = 1, and skips the tracker merge, so the evaluation result exists only on stdout. The report generation itself succeeded; only persistence failed.","triggerScenarios":"writeFileSync(trackerPath, ...) or the report write throwing because the reports/ or batch/tracker-additions/ directory doesn't exist (ENOENT), the disk is full (ENOSPC), permissions deny writing (EACCES/EROFS), or an invalid character/permission issue on the target path.","commonSituations":"Fresh checkout where reports/ or batch/tracker-additions/ was never created (and is gitignored so absent after clone); running in a read-only container or CI workspace; disk quota exceeded after large batch runs; path constructed from a company slug containing characters invalid on the filesystem.","solutions":["Read the err.message (ENOENT/EACCES/ENOSPC) and fix the root cause: mkdir -p reports batch/tracker-additions before running.","Ensure the process has write permission to the repo directory (check ownership, container mounts, read-only FS).","Free disk space if ENOSPC, or point output at a writable directory.","Re-run the evaluation — the report was not persisted, so it must be regenerated (or copy it from stdout if captured)."],"exampleFix":"// before (assumes dirs exist)\nwriteFileSync(join(PATHS.reports, filename), report);\n// after\nimport { mkdirSync } from 'node:fs';\nmkdirSync(PATHS.reports, { recursive: true });\nmkdirSync(join(CODE_ROOT, 'batch/tracker-additions'), { recursive: true });\nwriteFileSync(join(PATHS.reports, filename), report);","handlingStrategy":"validation","validationCode":"import { mkdirSync, accessSync, constants } from 'node:fs';\nfor (const dir of ['reports', 'batch/tracker-additions', 'data']) {\n  mkdirSync(dir, { recursive: true });\n  accessSync(dir, constants.W_OK); // throws early if not writable\n}","typeGuard":null,"tryCatchPattern":"try {\n  writeFileSync(target, contents);\n} catch (err) {\n  if (err.code === 'ENOENT') mkdirSync(dirname(target), { recursive: true });\n  if (err.code === 'ENOSPC') console.error('Disk full — free space and retry');\n  if (['EACCES', 'EROFS'].includes(err.code)) console.error(`No write permission on ${target}`);\n  process.exitCode = 1;\n}","preventionTips":["Pre-create reports/ and batch/tracker-additions/ (mkdir -p) in your run script or Makefile.","Check available disk space before large batch runs.","Run inside a writable workspace — avoid read-only container mounts for the repo directory.","Capture stdout when running headless so a failed save doesn't lose the report text."],"tags":["file-write","filesystem","nodejs","cli"],"backgroundTag":"file-write-failed","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}