affaan-m/ECC · error · Error
projectRoot or repoRoot is required for project install targ
Error message
projectRoot or repoRoot is required for project install targets
What it means
Thrown by resolveBaseRoot() in install-targets/helpers.js when scope is 'project' but neither input.projectRoot nor input.repoRoot is provided. Project-scoped adapters (cursor-project, claude-project, opencode project mode, etc.) need a concrete directory to write into — they cannot infer one. The guard exists so the failure surfaces at planning time rather than at file-write time.
Source
Thrown at scripts/lib/install-targets/helpers.js:48
for (const [prefix, ownerTarget] of Object.entries(PLATFORM_SOURCE_PATH_OWNERS)) {
if (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`)) {
return ownerTarget !== adapterTarget;
}
}
return false;
}
function resolveBaseRoot(scope, input = {}) {
if (scope === 'home') {
return input.homeDir || os.homedir();
}
if (scope === 'project') {
const projectRoot = input.projectRoot || input.repoRoot;
if (!projectRoot) {
throw new Error('projectRoot or repoRoot is required for project install targets');
}
return projectRoot;
}
throw new Error(`Unsupported install target scope: ${scope}`);
}
function buildValidationIssue(severity, code, message, extra = {}) {
return {
severity,
code,
message,
...extra,
};
}
function listRelativeFiles(dirPath, prefix = '') {
if (!fs.existsSync(dirPath)) {View on GitHub (pinned to 01e15490f0)
Solutions
- Pass projectRoot explicitly: adapter.resolveRoot({ projectRoot: process.cwd() }).
- If repoRoot is the intended install root, pass that instead — resolveBaseRoot accepts either.
- Switch to a home-scoped adapter (adapter.scope === 'home') if you want to install into ~/.claude etc.
- Validate the input shape before planning: assert(input.projectRoot || input.repoRoot).
Example fix
// before
adapter.resolveRoot({ homeDir: os.homedir() }); // missing projectRoot for project adapter
// after
adapter.resolveRoot({ projectRoot: process.cwd(), homeDir: os.homedir() }); Defensive patterns
Strategy: validation
Validate before calling
const projectRoot = input.projectRoot || input.repoRoot || process.cwd();
if (!projectRoot) {
throw new Error('Cannot resolve project root — pass projectRoot or run from a project directory.');
}
adapter.resolveRoot({ ...input, projectRoot }); Type guard
/** @param {unknown} v */
function hasProjectRoot(v) {
return typeof v === 'object' && v !== null
&& (typeof v.projectRoot === 'string' || typeof v.repoRoot === 'string');
} Prevention
- Always pass projectRoot explicitly to project-scoped adapters — never assume cwd.
- Confirm the adapter's scope before constructing input: home adapters do not need projectRoot.
When it happens
Trigger: Calling an adapter's planOperations / resolveRoot with an input object missing both projectRoot and repoRoot. Typically happens when a wrapper forwards only homeDir (intending a home install) but the adapter kind is 'project'.
Common situations: User ran the installer from a context with no cwd (some CI runners); a wrapper script destructured the wrong fields; adapter.kind and the supplied roots disagree (project adapter + home-only input).
Related errors
- Refusing to read non-file path: ${filePath}
- Missing source file for repair: ${sourcePath || operation.so
- An install component ID is required
- No legacy languages were provided
- Multiple ECC repo roots detected: ${uniqueRepoRoots.join(',
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/3b2ceddbdf23c320.
Report an issue: GitHub.