affaan-m/ECC · error · Error
Failed to save package manager config to ${configPath}: ${er
Error message
Failed to save package manager config to ${configPath}: ${err.message} What it means
Thrown by setProjectPackageManager when writeFile(configPath, ...) fails while writing the project-level preference file at <projectDir>/.claude/package-manager.json. Unlike saveConfig (global), this writes directly via utils.writeFile without first ensuring the .claude directory exists, so a missing <projectDir>/.claude is the most common cause (ENOENT). The underlying error and the resolved configPath are included for diagnosis.
Source
Thrown at scripts/lib/package-manager.js:281
* Set project's preferred package manager
*/
function setProjectPackageManager(pmName, projectDir = process.cwd()) {
if (!PACKAGE_MANAGERS[pmName]) {
throw new Error(`Unknown package manager: ${pmName}`);
}
const configDir = path.join(projectDir, '.claude');
const configPath = path.join(configDir, 'package-manager.json');
const config = {
packageManager: pmName,
setAt: new Date().toISOString()
};
try {
writeFile(configPath, JSON.stringify(config, null, 2));
} catch (err) {
throw new Error(`Failed to save package manager config to ${configPath}: ${err.message}`);
}
return config;
}
// Allowed characters in script/binary names: alphanumeric, dash, underscore, dot, slash, @
// This prevents shell metacharacter injection while allowing scoped packages (e.g., @scope/pkg)
const SAFE_NAME_REGEX = /^[@a-zA-Z0-9_./-]+$/;
/**
* Get the command to run a script
* @param {string} script - Script name (e.g., "dev", "build", "test")
* @param {object} options - { projectDir }
* @throws {Error} If script name contains unsafe characters
*/
function getRunCommand(script, options = {}) {
if (!script || typeof script !== 'string') {
throw new Error('Script name must be a non-empty string');
}View on GitHub (pinned to 01e15490f0)
Solutions
- Create <projectDir>/.claude before calling: fs.mkdirSync(path.join(projectDir,'.claude'), { recursive:true }).
- Pass a projectDir that exists and is writable.
- Remove a conflicting directory/file at <projectDir>/.claude/package-manager.json.
- Free disk space or remount read-write if the project is on a read-only filesystem.
Example fix
// before: .claude does not exist yet -> writeFile throws ENOENT
setProjectPackageManager('pnpm', projectDir); // throws [299]
// after: ensure the config dir exists first
const fs = require('fs'); const path = require('path');
fs.mkdirSync(path.join(projectDir, '.claude'), { recursive: true });
setProjectPackageManager('pnpm', projectDir); Defensive patterns
Strategy: try-catch
Validate before calling
const fs = require('fs'); const path = require('path');
function assertProjectConfigWritable(projectDir) {
const dir = path.join(projectDir, '.claude');
fs.mkdirSync(dir, { recursive: true });
const probe = path.join(dir, '.ecc-write-probe');
fs.writeFileSync(probe, ''); fs.unlinkSync(probe);
}
assertProjectConfigWritable(projectDir);
setProjectPackageManager('pnpm', projectDir); Type guard
null
Try / catch
try {
setProjectPackageManager(pmName, projectDir);
} catch (err) {
if (/Failed to save package manager config to/.test(err.message)) {
// most common cause: <projectDir>/.claude missing. Create it and retry.
fs.mkdirSync(path.join(projectDir, '.claude'), { recursive: true });
setProjectPackageManager(pmName, projectDir);
} else throw err;
} Prevention
- Create <projectDir>/.claude before calling; utils.writeFile does not mkdir parents.
- Pass a projectDir that exists and is writable; do not rely on cwd inside sandboxes.
- Remove any directory/file conflicting with package-manager.json.
- Ensure the project filesystem is mounted read-write.
When it happens
Trigger: Fires in the catch of writeFile inside setProjectPackageManager. Occurs when <projectDir>/.claude does not exist (utils.writeFile may not mkdir parents), when the project dir is read-only, when configPath resolves to an existing directory, on ENOSPC, or when projectDir itself does not exist.
Common situations: First-time project setup where .claude was never created; projectDir passed as a non-existent path; running in a fresh checkout without the .claude dir; read-only project mount; projectDir defaulting to process.cwd() inside a sandbox where cwd is not writable; an existing directory named package-manager.json.
Related errors
- Failed to save package manager preference: ${err.message}
- Failed to read ${normalizePath(path.relative(ROOT, outputPat
- ${label} destination is not writable by the current user: ${
- Failed to create directory '${dirPath}': ${err.message}
- Multiple ECC repo roots detected: ${uniqueRepoRoots.join(',
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/88d4d4c59d34aa5e.
Report an issue: GitHub.