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.

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)

Solutions

  1. Run `bun run codex:dev -- status` to see the reported state
  2. For 'collision': back up and remove the non-symlink directory/file at collectionPath yourself, then retry
  3. For 'broken': delete the dangling symlink (`rm <collectionPath>`) or restore the missing checkout, then retry
  4. 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

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


AI-assisted analysis of EveryInc/compound-engineering-plugin@c9c10f8c75 (2026-08-31). Data as JSON: /api/errors/11f98a8ca13d13c0. Report an issue: GitHub.