EveryInc/compound-engineering-plugin · error · Error
Cannot switch to local mode while the local collection is
Error message
Cannot switch to local mode while the local collection is ${previous.kind} What it means
switchToLocal() only proceeds when the collection path is 'absent' or already a 'valid' managed link. Any other state (collision, unrelated, broken) is rejected up front with this error, so the caller fixes the path state before activation can be attempted.
Solutions
- Run `bun run codex:dev -- status` to see the reported state
- For 'collision': back up and remove the non-symlink directory/file at collectionPath yourself, then retry
- For 'broken': delete the dangling symlink (`rm <collectionPath>`) or restore the missing checkout, then retry
- For 'unrelated': re-point or remove the foreign symlink once confirmed it is not needed, then retry
Example fix
# before (dangling link from a deleted checkout) $ bun run codex:dev -- local // Error: Cannot switch to local mode while the local collection is broken # after $ rm /path/to/CODEX_HOME/skills/compound-engineering-local $ bun run codex:dev -- local # now state is 'absent' and activation proceeds
Defensive patterns
Strategy: validation
Validate before calling
const state = await inspectLocalCollection(context);
if (state.kind !== "absent" && state.kind !== "valid") {
// remediate first: rm dangling/foreign links, move aside real dirs
console.warn(`collection is ${state.kind}; fix before switching to local`);
} else {
await switchToLocal(context);
} Type guard
function canSwitchToLocal(s: { kind: string }): boolean {
return s.kind === "absent" || s.kind === "valid";
} Try / catch
try {
await switchToLocal(context);
} catch (e) {
if (String(e).includes("Cannot switch to local mode")) {
const kind = String(e).match(/collection is (\w+)/)?.[1];
console.error(`remediate state '${kind}' (see status), then retry`);
} else throw e;
} Prevention
- Check `bun run codex:dev -- status` before every mode switch
- Keep the checkout path stable so links never dangle
- Remove foreign or manual entries at the collection path before installing
When it happens
Trigger: Calling switchToLocal() (via runCodexDevCommand or status-driven flows) when inspectLocalCollection returns kind='collision' (real file/dir), 'unrelated' (symlink outside a CE checkout), or 'broken' (dangling symlink).
Common situations: A real skills directory or another plugin's symlink already occupies the collection path; the previous local checkout was deleted leaving a dangling link; a hand-made symlink to the wrong repository.
Related errors
- changed since it was inspected; refusing to remove it ` …
- changed since it was inspected; refusing to remove it. The…
- exists and is not a symlink; refusing to remove it
- is a broken symlink; refusing to overwrite it
- is a broken symlink; refusing to remove it automatically
AI-assisted analysis of EveryInc/compound-engineering-plugin@c9c10f8c75 (2026-08-31).
Data as JSON: /api/errors/11f98a8ca13d13c0.
Report an issue: GitHub.
Appendix: source
Thrown at src/dev/codex-dev.ts:560
plugins.some((plugin) => plugin.pluginId === OFFICIAL_PLUGIN_ID) ||
(await isOfficialPluginConfigured(context))
) {
await runCodex(context, runner, ["plugin", "remove", OFFICIAL_PLUGIN_ID, "--json"])
}
await removePlugins(
context,
runner,
plugins.filter((plugin) => plugin.pluginId !== OFFICIAL_PLUGIN_ID),
)
}
export async function switchToLocal(
context: CodexDevContext,
runner: CommandRunner = new BunCommandRunner(),
): Promise<CodexDevStatus> {
const previous = await inspectLocalCollection(context)
if (previous.kind !== "absent" && previous.kind !== "valid") {
throw new Error(`Cannot switch to local mode while the local collection is ${previous.kind}`)
}
const activatedTarget = await fs.realpath(context.skillsRoot)
await activateLocalCollection(context)
try {
const plugins = await listCompoundEngineeringPlugins(context, runner)
await removeLocalPluginConflicts(context, runner, plugins)
const status = await inspectCodexDevStatus(context, runner)
if (status.mode !== "local") {
throw new Error(`Could not verify local Codex development mode (reported ${status.mode})`)
}
return status
} catch (error) {
await restoreLocalCollection(context, previous, activatedTarget)
throw error
}
}
async function listMarketplaces(context: CodexDevContext, runner: CommandRunner): Promise<Marketplace[]> {View on GitHub (pinned to c9c10f8c75)