affaan-m/ECC · error · Error
Harness capability root is out of sync for target ${declared
Error message
Harness capability root is out of sync for target ${declaredScope.targetId} What it means
The third require-time validation: every harness scope declares a display root (like './.cursor' or '~/.config/opencode'), and validateCatalog recomputes the expected root from the scope's adapter — home adapters get a '~/...' prefix, project adapters get './...' plus the OS-normalized relative path — and requires an exact string match. A moved directory, changed prefix, or Windows path separator produces this mismatch at module load.
Source
Thrown at scripts/lib/harness-capabilities.js:281
if (new Set(catalogTargetIds).size !== catalogTargetIds.length) {
throw new Error('Harness capability catalog contains duplicate install target ids');
}
const supported = [...SUPPORTED_INSTALL_TARGETS].sort();
const registered = adapters.map(adapter => adapter.target).sort();
const catalogued = [...catalogTargetIds].sort();
if (
JSON.stringify(catalogued) !== JSON.stringify(supported)
|| JSON.stringify(catalogued) !== JSON.stringify(registered)
) {
throw new Error('Harness capability catalog is out of sync with install targets');
}
for (const harness of HARNESS_CAPABILITIES) {
for (const declaredScope of harness.scopes) {
const adapter = adapterByTarget.get(declaredScope.targetId);
if (!adapter || expectedRootForAdapter(adapter) !== declaredScope.root) {
throw new Error(
`Harness capability root is out of sync for target ${declaredScope.targetId}`
);
}
}
}
}
validateCatalog();
function listHarnessCapabilities() {
return HARNESS_CAPABILITIES.slice();
}
function listGuidedHarnesses() {
return GUIDED_HARNESS_IDS.map(id => LOOKUP.get(id));
}
function getHarnessCapability(value) {View on GitHub (pinned to d8409a4b08)
Solutions
- Recompute the correct value: for the offending targetId, run the same logic as expectedRootForAdapter (prefix from adapter.kind, then path.relative(baseRoot, adapter.resolveRoot(...)) with backslashes converted to '/')
- Paste that exact string into the harness's scopes[].root declaration
- Keep roots computed rather than hand-maintained where possible so they cannot drift
- Re-require the module to confirm the whole validateCatalog() chain passes
Example fix
// before
{ targetId: 'cursor', root: '~/.cursor' } // adapter is project-scoped
// after
{ targetId: 'cursor', root: './.cursor' } Defensive patterns
Strategy: validation
Validate before calling
// CI guard: declared scope roots must equal recomputed roots
const caps = require('./scripts/lib/harness-capabilities.js');
const { listInstallTargetAdapters } = require('./scripts/lib/install-targets');
// recompute like expectedRootForAdapter does and compare, e.g.:
// prefix = adapter.kind === 'home' ? '~/' : './';
// expected = prefix + path.relative(baseRoot, adapter.resolveRoot(...)).replace(/\\/g, '/');
// assert declaredScope.root === expected for every scope Prevention
- After touching any adapter's install root, re-require harness-capabilities.js locally before pushing
- Prefer deriving scope roots from adapters over hand-maintained literals
- Normalize path separators to '/' and use the correct ~/ vs ./ prefix for adapter kind
When it happens
Trigger: An adapter's resolved install root changes (directory moved or its kind flips between home and project) while the harness entry's scopes[].root still holds the old literal string; or the root was written with backslashes / wrong prefix.
Common situations: Refactoring an adapter to install into a different folder; porting roots between home-scoped and project-scoped targets; editing the declared root string by hand and introducing a typo; path separator differences when validating on Windows.
Related errors
- Harness capability catalog contains duplicate install target
- Harness capability catalog is out of sync with install targe
- Missing value for --family
- Missing value for --target
- Unknown argument: ${arg}
AI-assisted analysis of affaan-m/ECC@d8409a4b08 (2026-08-26).
Data as JSON: /api/errors/56194bb2cc3c0a14.
Report an issue: GitHub.