paperclipai/paperclip · error · Error
codex auth cache: ${label} is empty
Error message
codex auth cache: ${label} is empty What it means
Thrown by toSafePathSegment in the codex auth cache when a value used as a path segment is empty after trimming. The cache stores per-identity Codex credentials under companies/<companyId>/codex-auth-cache/<accountId>/auth.json, so each segment must be a real basename; an empty value would collapse the path and is treated as a fail-loud security defect (Security condition 3).
Source
Thrown at packages/adapters/codex-local/src/server/codex-auth-cache.ts:72
* (`0`, `false`, `no`, or `off`).
*/
export function isCodexAuthCacheEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
const raw = env[CODEX_AUTH_CACHE_OFF_SWITCH_ENV];
if (typeof raw !== "string") return true;
return !FALSY_ENV_RE.test(raw.trim());
}
/**
* Sanitizes one raw value to a single safe path segment. Rejects an empty value,
* a relative segment (`.` or `..`), a path separator (`/` or `\`), and a NUL
* byte, so the value can never become a path traversal. Returns the trimmed,
* safe segment. The `label` names the value in the error message. (Security
* condition 3.)
*/
function toSafePathSegment(value: string, label: string): string {
const trimmed = typeof value === "string" ? value.trim() : "";
if (trimmed.length === 0) {
throw new Error(`codex auth cache: ${label} is empty`);
}
if (trimmed === "." || trimmed === "..") {
throw new Error(`codex auth cache: ${label} is a relative path segment`);
}
if (trimmed.includes("/") || trimmed.includes("\\") || trimmed.includes("\0")) {
throw new Error(`codex auth cache: ${label} contains a path separator`);
}
// Defense in depth: a safe segment is exactly its own basename. Anything else
// carries a separator or a relative segment the checks above must have caught.
if (path.basename(trimmed) !== trimmed) {
throw new Error(`codex auth cache: ${label} is not a single path segment`);
}
return trimmed;
}
/**
* Sanitizes an `account_id` to one safe path segment. Rejects an empty value, a
* relative segment (`.` or `..`), a path separator, and a NUL byte, so a rawView on GitHub (pinned to 67001ec6eb)
Solutions
- Ensure the Codex auth.json being cached has a non-empty tokens.account_id (re-run codex login so the account id is populated).
- Ensure the companyId passed to resolveCodexAuthCacheDir is a real, non-empty company id.
- If you intentionally have API-key-only credentials with no account_id, disable the cache via PAPERCLIP_CODEX_AUTH_CACHE=0 so the vend path is skipped.
Example fix
// before
toCacheKey(auth.tokens?.account_id ?? "")
// after — guard before caching
const accountId = auth.tokens?.account_id;
if (accountId && accountId.trim()) { toCacheKey(accountId); } Defensive patterns
Strategy: validation
Validate before calling
function hasNonEmptySegment(value: unknown): value is string {
return typeof value === "string" && value.trim().length > 0;
}
// before caching
if (!hasNonEmptySegment(accountId)) { /* skip cache vend, or disable cache */ } Type guard
function isNonEmptySafeSegment(value: unknown): value is string {
if (typeof value !== "string") return false;
const t = value.trim();
return t.length > 0 && t !== "." && t !== ".." && !t.includes("/") && !t.includes("\\") && !t.includes("\0");
} Try / catch
try {
const key = toCacheKey(accountId);
} catch (e) {
if (e instanceof Error && /codex auth cache: .* is empty/.test(e.message)) {
// credential has no account_id; skip the cache path, do not crash the run
} else throw e;
} Prevention
- Validate account_id/companyId are non-empty opaque ids before they reach the cache layer.
- For API-key-only auth.json (no account_id), set PAPERCLIP_CODEX_AUTH_CACHE=0.
- Never feed test placeholder ids (".", "") into cache paths; assert in fixtures.
When it happens
Trigger: toCacheKey(accountId) is called with an empty/whitespace accountId (e.g. the auth.json had no account_id), or resolveCodexAuthCacheDir(env, companyId) is called with an empty companyId. The label in the message identifies which value was empty ("account_id" or "companyId").
Common situations: A Codex auth.json is an API-key-only file with no tokens.account_id, so the cache write path receives an empty accountId; or a code path constructs the cache dir with a missing company id during a test/migration.
Related errors
- codex auth cache: ${label} is a relative path segment
- Refusing to write export file outside output directory: ${re
- Invalid object key for company ${companyId}.
- sync operation ${label} path is not a confined absolute path
- sync operation ${label} path escapes its confinement root: $
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/40cd11dea8b0b189.
Report an issue: GitHub.