Yeachan-Heo/oh-my-codex · error · Error

[native-assets] unable to create cache root

Error message

[native-assets] unable to create cache root

What it means

The configured native cache root could not be created (or canonicalized) — canonicalCacheRoot returned undefined after attempting mkdir(recursive). Without a usable root, managed binary publication cannot proceed.

Source

Thrown at src/cli/native-assets.ts:620

    if (!sameFile(lock.identity, reopened) || reopened.text !== lock.record) return { state: 'cleanup-failed' };
    const current = await lstat(lock.path);
    if (!sameFile(lock.identity, { dev: current.dev, ino: current.ino, size: current.size }) || !current.isFile() || current.nlink !== 1) return { state: 'cleanup-failed' };
    await unlink(lock.path);
  } catch (error) { return absent(error) ? undefined : { state: 'cleanup-failed' }; }
  return undefined;
}

async function quarantineInvalid(path: string): Promise<void> {
  try {
    await lstat(path);
    await rename(path, `${path}.quarantine.${uuid()}`);
  } catch (error) { if (!absent(error)) throw error; }
}

async function publishManagedNativeBinary(source: string, destination: string, platform: NodeJS.Platform, env: NodeJS.ProcessEnv): Promise<string | undefined> {
  const configuredRoot = resolveNativeCacheRoot(env);
  const root = await canonicalCacheRoot(configuredRoot, true);
  if (!root) throw new Error('[native-assets] unable to create cache root');
  destination = canonicalDescendantPath(destination, configuredRoot, root);
  await validateDescendant(destination, root, true);
  const lock = await acquireCacheLock(destination, env);
  const attempt = uuid();
  const tempBinary = join(dirname(destination), `.${attempt}.tmp.bin`);
  const tempSidecar = join(dirname(destination), `.${attempt}.tmp.sha256`);
  const revalidatePublicationPaths = async (): Promise<void> => {
    await validateDescendant(destination, root, false);
    await validateDescendant(sidecarPath(destination), root, false);
    await validateDescendant(lock.path, root, false);
    await validateDescendant(tempBinary, root, false);
    await validateDescendant(tempSidecar, root, false);
  };
  let primaryError: unknown;
  try {
    await revalidatePublicationPaths();
    const existing = await inspectManagedNativeBinary(destination, env);
    if (existing.state === 'verified') return existing.path;

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Fix permissions/ownership of the cache root path (chown -R $(whoami)).
  2. Set the cache-root env override to a writable location (e.g. a tmpfs or project-local dir).
  3. In containers, ensure HOME and the cache dir are on a writable volume.

Example fix

# before: cache root /root/.cache/omx owned by root, running as app
sudo chown -R app:app /root/.cache/omx
# or: export OMX_NATIVE_CACHE_ROOT=/tmp/omx-cache  # (use the library's documented override)
Defensive patterns

Strategy: validation

Validate before calling

import { accessSync, constants } from 'node:fs';
function cacheRootWritable(root: string): boolean { try { accessSync(root, constants.W_OK | constants.X_OK); return true; } catch { try { accessSync(require('node:path').dirname(root), constants.W_OK); return true; } catch { return false; } } }

Try / catch

try { await hydrateNativeBinary(); } catch (e) { if (/unable to create cache root/.test(String(e))) { /* chown/chmod the cache dir or point env override at a writable path */ } throw e; }

Prevention

When it happens

Trigger: publishManagedNativeBinary when the cache root path is unwritable (EACCES), sits on a read-only mount, or its parent cannot be traversed; canonicalCacheRoot swallows absent errors but fails to produce a canonical root.

Common situations: Running as a user without write access to the default cache location (e.g. root-owned ~/.cache after sudo misuse); read-only container filesystems; XDG-style env overrides pointing to invalid paths.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/a5fa11c6e4f0f99b. Report an issue: GitHub.