{"record":{"id":"eb1c80e5f5ba1d0d","repo":"affaan-m/ECC","slug":"failed-to-write-path-basename-filepath-error-message","errorCode":null,"errorMessage":"Failed to write ${path.basename(filePath)}: ${error.message}","messagePattern":"Failed to write (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/ci/catalog.js","lineNumber":76,"sourceCode":"    agents: { count: agents.length, files: agents, glob: 'agents/*.md' },\n    commands: { count: commands.length, files: commands, glob: 'commands/*.md' },\n    skills: { count: skills.length, files: skills, glob: 'skills/*/SKILL.md' }\n  };\n}\n\nfunction readFileOrThrow(filePath) {\n  try {\n    return fs.readFileSync(filePath, 'utf8');\n  } catch (error) {\n    throw new Error(`Failed to read ${path.basename(filePath)}: ${error.message}`);\n  }\n}\n\nfunction writeFileOrThrow(filePath, content) {\n  try {\n    fs.writeFileSync(filePath, content, 'utf8');\n  } catch (error) {\n    throw new Error(`Failed to write ${path.basename(filePath)}: ${error.message}`);\n  }\n}\n\nfunction replaceOrThrow(content, regex, replacer, source) {\n  if (!regex.test(content)) {\n    throw new Error(`${source} is missing the expected catalog marker`);\n  }\n\n  return content.replace(regex, replacer);\n}\n\nfunction parseReadmeExpectations(readmeContent) {\n  const expectations = [];\n\n  const quickStartMatch = readmeContent.match(\n    /access to\\s+(\\d+)\\s+agents,\\s+(\\d+)\\s+skills,\\s+and\\s+(\\d+)\\s+(?:commands|legacy command shims?)/i\n  );\n  if (!quickStartMatch) {","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/ci/catalog.js#L58-L94","documentation":"writeFileOrThrow wraps fs.writeFileSync for the CI catalog sync, converting write failures (EACCES, EISDIR, ENOSPC, read-only FS) into a clear Error naming the target file's basename plus the underlying Node error message. It is called when the check regenerates or patches catalog files.","triggerScenarios":"runCatalogCheck (or fix mode) attempting to rewrite a catalog file while the path is unwritable: read-only checkout, root-owned file, target is a directory, or disk full.","commonSituations":"CI runners checking out code with read-only permissions; running the fixer as a non-root user against root-owned generated files; out-of-disk containers; accidentally pointing at a directory path; Docker builds with a read-only layer.","solutions":["Fix write permissions on the file (chown/chmod) or run as a user that owns the checkout","Ensure the checkout is writable (drop :ro mounts, remount rw)","Verify the path is a file, not a directory, and the parent directory exists","Free disk space if the message shows ENOSPC"],"exampleFix":"// before (root-owned file)\nError: Failed to write install-components.json: EACCES...\n// after\nsudo chown -R $(whoami) manifests/\nnode scripts/ci/catalog.js fix","handlingStrategy":"try-catch","validationCode":"const fs = require('fs');\nfs.accessSync(path.dirname(filePath), fs.constants.W_OK); // throws early if dir unwritable\nif (fs.existsSync(filePath)) fs.accessSync(filePath, fs.constants.W_OK);","typeGuard":"function isWritableFile(p) {\n  try {\n    const st = fs.statSync(p);\n    return st.isFile() && fs.accessSync(p, fs.constants.W_OK) === undefined;\n  } catch { return false; }\n}","tryCatchPattern":"try {\n  writeFileOrThrow(filePath, content);\n} catch (err) {\n  if (/^Failed to write/.test(err.message)) {\n    console.error(`Cannot write ${filePath}: ${err.message}. Check permissions/read-only FS.`);\n    process.exit(1);\n  }\n  throw err;\n}","preventionTips":["Ensure CI checkouts are writable when running fix/sync modes","Run generated-file fixers as the checkout's owner, not root against root-owned files","Confirm target paths are files, not directories","Monitor disk space in CI containers"],"tags":["filesystem","file-write","ci"],"backgroundTag":"file-write-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}