thedotmack/claude-mem · error

Could not locate a Codex marketplace root with…

Error message

Could not locate a Codex marketplace root with .agents/plugins/marketplace.json and plugin/.codex-plugin/plugin.json. Run npx claude-mem@latest install from the package or repo root.

What it means

resolvePluginMarketplaceRoot() walks a list of candidate directories (and their ancestors) looking for one that has both .agents/plugins/marketplace.json and plugin/.codex-plugin/plugin.json. When no candidate resolves to a complete marketplace root, it throws with instructions to run the installer from the package or repo root. This is the fallback error when the Codex install cannot self-locate its marketplace.

Solutions

  1. cd into the claude-mem package or repo root (the one containing .agents/plugins/marketplace.json) and run npx claude-mem@latest install.
  2. Verify both markers exist: ls .agents/plugins/marketplace.json plugin/.codex-plugin/plugin.json; create/restore them from a complete checkout if absent.
  3. Pass an explicit preferredRoot pointing at the correct marketplace root so the ancestor search is not needed.

Example fix

// before: run from an unrelated directory
npx claude-mem@latest install
// Error: Could not locate a Codex marketplace root...

// after: run from the repo root with the marker files
cd ~/code/claude-mem && npx claude-mem@latest install
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'fs';
import path from 'path';
function findMarketplaceRoot(start: string): string | null {
  let dir = path.resolve(start);
  while (true) {
    if (existsSync(path.join(dir, '.agents/plugins/marketplace.json')) &&
        existsSync(path.join(dir, 'plugin/.codex-plugin/plugin.json'))) return dir;
    const parent = path.dirname(dir);
    if (parent === dir) return null;
    dir = parent;
  }
}

Try / catch

try {
  installCodexPlugin();
} catch (err) {
  if (err instanceof Error && err.message.includes('Could not locate a Codex marketplace root')) {
    console.error('Run npx claude-mem@latest install from the repo root containing .agents/plugins/marketplace.json');
  } else throw err;
}

Prevention

When it happens

Trigger: marketplaceRoot() -> resolvePluginMarketplaceRoot() is called (no preferredRoot, or the preferred root also failed) and every candidate, including all ancestors via findAncestorWithCodexMarketplace, is missing one or both required marker files.

Common situations: Running the CLI from an arbitrary directory (e.g. ~ or a script dir) far from any checkout; invoking from an npm global install where dot-directories were stripped; a fresh clone with .agents/ gitignored; a repo restructured so the marker files moved.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/0198768c4d783795. Report an issue: GitHub.

Appendix: source

Thrown at src/services/integrations/CodexCliInstaller.ts:125

function resolvePluginMarketplaceRoot(preferredRoot?: string): string {
  if (preferredRoot) {
    return assertCodexMarketplaceRoot(preferredRoot);
  }

  const candidates = [
    process.env.CLAUDE_PLUGIN_ROOT,
    process.env.PLUGIN_ROOT,
    process.cwd(),
    path.dirname(fileURLToPath(import.meta.url)),
  ].filter((value): value is string => Boolean(value));

  for (const candidate of candidates) {
    const resolved = findAncestorWithCodexMarketplace(candidate);
    if (resolved && missingMarketplaceFiles(resolved).length === 0) return resolved;
  }

  throw new Error('Could not locate a Codex marketplace root with .agents/plugins/marketplace.json and plugin/.codex-plugin/plugin.json. Run npx claude-mem@latest install from the package or repo root.');
}

function lookupCodexOnWindows(): string | null {
  let stdout: string;
  try {
    stdout = execFileSync('where.exe', ['codex'], {
      encoding: 'utf-8',
      stdio: ['ignore', 'pipe', 'ignore'],
      windowsHide: true,
    });
  } catch (error) {
    const err = error instanceof Error ? error : new Error(String(error));
    logger.warn('WORKER', 'Failed to locate codex via where; falling back to codex.cmd', { command: 'where codex' }, err);
    return null;
  }

  const candidates = stdout
    .split(/\r?\n/)

View on GitHub (pinned to d8bc9755e7)