{"record":{"id":"acbe289b9d490f98","repo":"upstash/context7","slug":"failed-to-write-to-skillpath-error-message","errorCode":null,"errorMessage":"Failed to write to ${skillPath}: ${error.message}","messagePattern":"Failed to write to (.+?): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/cli/src/commands/generate.ts","lineNumber":533,"sourceCode":"\n  for (const targetDir of targetDirs) {\n    let finalDir = targetDir;\n    if (options.output && !targetDir.includes(\"/.config/\") && !targetDir.startsWith(homedir())) {\n      finalDir = targetDir.replace(process.cwd(), options.output);\n    }\n    const skillDir = join(finalDir, skillName);\n    const skillPath = join(skillDir, \"SKILL.md\");\n\n    try {\n      await mkdir(skillDir, { recursive: true });\n      await writeFile(skillPath, generatedContent!, \"utf-8\");\n    } catch (err) {\n      const error = err as NodeJS.ErrnoException;\n      if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n        permissionError = true;\n        failedDirs.add(skillDir);\n      } else {\n        log.warn(`Failed to write to ${skillPath}: ${error.message}`);\n      }\n    }\n  }\n\n  if (permissionError) {\n    writeSpinner.fail(pc.red(\"Permission denied\"));\n    log.blank();\n    console.log(pc.yellow(\"Fix permissions with:\"));\n    for (const dir of failedDirs) {\n      const parentDir = join(dir, \"..\");\n      console.log(pc.dim(`  sudo chown -R $(whoami) \"${parentDir}\"`));\n    }\n    log.blank();\n    return;\n  }\n\n  writeSpinner.succeed(pc.green(`Created skill in ${targetDirs.length} location(s)`));\n  trackEvent(\"gen_install\");","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/upstash/context7/blob/5284672feb575908efead6fcf1b5e542f8d607bb/packages/cli/src/commands/generate.ts#L515-L551","documentation":"During skill-file installation in `generate`, write failures are classified: EACCES/EPERM routes to the permission-denied flow with `chown` hints, while every other errno (ENOSPC, EROFS, EISDIR, EMFILE...) is logged as a warning with the failing path and message, and that target is silently skipped — the command continues to the other targets.","triggerScenarios":"Disk full (ENOSPC); read-only filesystem such as a container volume or CI workspace (EROFS); an existing directory occupying the SKILL.md path (EISDIR); file-descriptor exhaustion (EMFILE).","commonSituations":"CI runners with full disks; Docker read-only mounts; a previous run or manual operation leaving a directory named SKILL.md; aggressive ulimits.","solutions":["Check the errno in the logged message: ENOSPC → free disk space; EROFS → write to a writable location via `--output`","Remove any directory conflicting with the SKILL.md file path","Raise the file-descriptor limit (ulimit -n) for EMFILE","Re-run generate after fixing and confirm the file exists at the printed path"],"exampleFix":"# before: read-only mount, warn + skipped\ncontext7 generate  # Failed to write to .../SKILL.md: EROFS: read-only file system\n\n# after: direct output to a writable dir\ncontext7 generate --output ./out","handlingStrategy":"validation","validationCode":"import { access } from 'fs/promises';\nasync function isWritable(dir: string): Promise<boolean> {\n  try { await access(dir === '' ? '.' : dir); return true; }\n  catch { return false; }\n}\nconst ok = await isWritable(skillDir).catch(() => false);\nif (!ok) throw new Error(`target not writable: ${skillDir}`);","typeGuard":"function isPermissionErrno(e: unknown): e is NodeJS.ErrnoException {\n  return (e as NodeJS.ErrnoException)?.code === 'EACCES' || (e as NodeJS.ErrnoException)?.code === 'EPERM';\n}","tryCatchPattern":"try {\n  await mkdir(skillDir, { recursive: true });\n  await writeFile(skillPath, content, 'utf-8');\n} catch (err) {\n  const code = (err as NodeJS.ErrnoException).code;\n  if (code === 'ENOSPC') throw new Error('disk full — free space or use --output');\n  if (code === 'EROFS') throw new Error('read-only filesystem — pass --output to a writable dir');\n  if (code === 'EISDIR') throw new Error(`remove the directory at ${skillPath} first`);\n  throw err;\n}","preventionTips":["Pre-check target writability before generating, not after","In containers/CI, write generated files to a writable workdir via --output","Watch disk space in CI runners; ENOSPC mid-write is the most common non-permission cause"],"tags":["cli","filesystem","generate","write","enospc"],"backgroundTag":"file-write-failed","analyzedSha":"5284672feb575908efead6fcf1b5e542f8d607bb","analyzedAt":"2026-08-18T18:00:18.510Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}