stablyai/orca · error · Error

Refusing to copy a config template from the primary ~/.codex

Error message

Refusing to copy a config template from the primary ~/.codex

What it means

Thrown by the Codex validation harness when --config-template points to a file inside the primary ~/.codex directory. The harness copies the template into the disposable home's ~/.codex/config.toml, and bootstrapping from the user's live Codex config would contaminate the validation boundary. The check uses realpath on the template and isWithin() against primaryHome/.codex.

Source

Thrown at config/scripts/run-codex-real-account-validation.mjs:149

    onboarding: { flowVersion: 2, closedAt: 1, outcome: 'completed', lastCompletedStep: 3 },
    ui: { contextualToursAutoEligible: false, projectOrderManualDefaultNoticeDismissed: true }
  }
  await writeFile(
    path.join(layout.userDataDir, 'orca-data.json'),
    `${JSON.stringify(profile, null, 2)}\n`
  )
}

async function installCodexConfigTemplate(layout, templatePath) {
  if (!templatePath) {
    return
  }
  const resolvedTemplate = await realpath(path.resolve(templatePath))
  const primaryCodexHome = path.join(layout.primaryHome, '.codex')
  // Why: validation must never bootstrap itself from the user's live Codex
  // configuration, even when a caller passes that path accidentally.
  if (isWithin(resolvedTemplate, primaryCodexHome)) {
    throw new Error('Refusing to copy a config template from the primary ~/.codex')
  }
  await mkdir(path.join(layout.homeDir, '.codex'), { recursive: true, mode: 0o700 })
  await copyFile(resolvedTemplate, path.join(layout.homeDir, '.codex', 'config.toml'))
}

async function fingerprintFile(filePath) {
  try {
    const stat = await lstat(filePath)
    if (!stat.isFile()) {
      return { exists: true, type: stat.isSymbolicLink() ? 'symlink' : 'other' }
    }
    const contents = await readFile(filePath)
    return {
      exists: true,
      type: 'file',
      size: stat.size,
      mtimeMs: stat.mtimeMs,
      sha256: createHash('sha256').update(contents).digest('hex')

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Create a config template outside ~/.codex (e.g. in the repo or /tmp) and pass that path.
  2. If you need a copy of your config, copy it out first: `cp ~/.codex/config.toml /tmp/codex-template.toml` then pass --config-template=/tmp/codex-template.toml.

Example fix

// before
node config/scripts/run-codex-real-account-validation.mjs --scenario codex-lb --config-template ~/.codex/config.toml
// after
cp ~/.codex/config.toml /tmp/codex-lb-template.toml
node config/scripts/run-codex-real-account-validation.mjs --scenario codex-lb --config-template /tmp/codex-lb-template.toml
Defensive patterns

Strategy: validation

Validate before calling

const resolvedTemplate = await realpath(path.resolve(templatePath))
const primaryCodexHome = path.join(primaryHome, '.codex')
if (isWithin(resolvedTemplate, primaryCodexHome)) {
  throw new Error('Config template must be outside the primary ~/.codex')
}

Type guard

function isOutsidePrimaryCodex(templateReal, primaryCodexHome) {
  return !isWithin(templateReal, primaryCodexHome)
}

Prevention

When it happens

Trigger: Passing --config-template ~/.codex/config.toml or any path that resolves (after symlinks) inside the primary ~/.codex directory. The codex-lb scenario requires a template, so this guard commonly pairs with that scenario.

Common situations: A developer points the template at their real Codex config by accident, or a symlink inside ~/.codex resolves the template path.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/287202a584766fc0. Report an issue: GitHub.