paperclipai/paperclip · error

codex auth cache: account-home directory no longer exists; r

Error message

codex auth cache: account-home directory no longer exists; refusing to write a secret that names it

What it means

assertAccountHomeCacheDirStillValid() checks that the account-home directory still exists on disk before createManagedLocalSecret() writes a secret whose name references that directory. If stat fails with ENOENT the directory is gone, and writing a secret pointing at a nonexistent home would leave dangling, unusable credentials — so the write is refused.

Source

Thrown at packages/adapters/codex-local/src/server/codex-auth-cache.ts:355

 * under the cache root can ever be an account-home directory, so this never
 * rejects an unrelated `local_encrypted` secret write, such as an API key or
 * a hand-typed token.
 */
export async function assertAccountHomeCacheDirStillValid(
  env: NodeJS.ProcessEnv = process.env,
  companyId: string,
  value: string,
): Promise<void> {
  const cacheRoot = resolveCodexAuthCacheDir(env, companyId);
  if (!value.startsWith(cacheRoot + path.sep)) return;
  const exists = await lstat(value)
    .then(() => true)
    .catch((error: NodeJS.ErrnoException) => {
      if (error.code === "ENOENT") return false;
      throw error;
    });
  if (!exists) {
    throw new Error(
      "codex auth cache: account-home directory no longer exists; refusing to write a secret that names it",
    );
  }
}

/**
 * Reads the usable subscription `account_id` from an `auth.json` payload. Returns
 * `null` for an absent, unusable, or api-key credential (no subscription
 * identity). This mirrors `parseAuth` in `codex-auth-merge-decision.cjs`; keep
 * the two in step when the auth format changes.
 *
 * The returned value is the exact, untrimmed `account_id` string. A caller
 * passes it on to {@link toAccountHandle} unchanged: that function is the
 * one place that decides whether surrounding whitespace is acceptable, and it
 * must see the raw value to reject an identifier that differs from another
 * one only by whitespace. Trimming here, before that check runs, would let
 * two distinct identifiers collapse onto the same account handle.
 */

View on GitHub (pinned to 01ad858492)

Solutions

  1. Recreate the account home by re-running the Codex device login / promotion so the directory is re-established, then retry the secret write.
  2. Verify the account-home directory path exists (fs.stat) and that the expected handle-derived directory is present before writing.
  3. If the account is genuinely gone, remove the stale secret/cache entry so it no longer references a missing home.
  4. Check nothing in your cleanup scripts or tmp cleaners deletes the Codex account-home directory while the adapter is using it.

Example fix

// before
await createManagedLocalSecret(secretService, { accountHandle, ... });
// after
const homeDir = resolveAccountHomeDir(accountHandle);
if (!existsSync(homeDir)) {
  throw new Error(`account home missing: ${homeDir}; re-run codex login before writing secrets`);
}
await createManagedLocalSecret(secretService, { accountHandle, ... });
Defensive patterns

Strategy: try-catch

Validate before calling

import { stat } from "node:fs/promises";
async function accountHomeExists(dir: string): Promise<boolean> {
  try { await stat(dir); return true; } catch (e: any) { if (e.code === "ENOENT") return false; throw e; }
}
if (!(await accountHomeExists(homeDir))) {
  await reRunCodexLogin(); // recreate home before any secret write
}

Try / catch

try {
  await createManagedLocalSecret(secretService, params);
} catch (err) {
  if (err instanceof Error && err.message.includes("account-home directory no longer exists")) {
    await reRunCodexLoginAndPromotion(); // rebuild home, then retry once
    await createManagedLocalSecret(secretService, params);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling createManagedLocalSecret() (directly or via secretService) after the account-home directory was deleted or moved — e.g. manual cleanup of ~/.codex or the cache root, an OS temp cleaner removing it, or a home migration that did not recreate the directory.

Common situations: User manually deleted the Codex home/account directory; disk cleanup tools purged cache dirs; the account was logged out elsewhere while the local secret store still references its home; workspace/container rebuilds wiping home directories but not secrets.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/1d150e97f702055a. Report an issue: GitHub.