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

[native-assets] incomplete lock write

Error message

[native-assets] incomplete lock write

What it means

While creating the publication lock file, a write to the freshly O_EXCL-created file reported fewer bytes than the lock record. This indicates a filesystem-level short write (disk full, quota, or exotic FS), so the lock would be corrupt and is rejected immediately.

Solutions

  1. Free space on the volume hosting the cache root.
  2. Point the cache root env var at a local, non-network filesystem.
  3. Re-run hydration once space is available.
Defensive patterns

Strategy: try-catch

Try / catch

try { await hydrateNativeBinary(); } catch (e) { if (/incomplete lock write/.test(String(e))) { /* free disk space, retry */ } throw e; }

Prevention

When it happens

Trigger: acquireCacheLock when handle.write of the lock record returns bytesWritten < record length — ENOSPC conditions, full tmpfs, or flaky network filesystems backing the cache.

Common situations: Docker containers with tiny tmpfs caches; disk-full CI runners; NFS-backed HOME directories.

Related errors


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

Appendix: source

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

  return { state: 'verified', path: effectiveBinaryPath!, lock: lockDiagnostic };
}

async function acquireCacheLock(binaryPath: string, env: NodeJS.ProcessEnv): Promise<PublicationLock> {

  const path = lockPath(binaryPath);
  const started = performance.now();
  const deadline = started + lockWaitMs(env);

  for (;;) {
    const token = uuid();
    const record = lockRecord(token, binaryPath);

    const recordBytes = Buffer.from(record, 'utf8');
    try {
      const handle = await open(path, constants.O_RDWR | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
      try {
        const { bytesWritten } = await handle.write(recordBytes, 0, recordBytes.length, 0);
        if (bytesWritten !== recordBytes.length) throw new Error('[native-assets] incomplete lock write');
        const readback = Buffer.alloc(recordBytes.length);
        const { bytesRead } = await handle.read(readback, 0, readback.length, 0);
        if (bytesRead !== readback.length || !readback.equals(recordBytes)) throw new Error('[native-assets] lock readback mismatch');
        const identity = await handle.stat();
        const fileIdentity = { dev: identity.dev, ino: identity.ino, size: identity.size };
        if (!identity.isFile() || identity.nlink !== 1) throw new Error('[native-assets] unsafe publication lock');
        await reInspectPath(path, fileIdentity, true);
        return { path, token, record, identity: fileIdentity };

      } finally { await handle.close(); }
    } catch (error) {
      if (errno(error) !== 'EEXIST') throw error;
      if (performance.now() >= deadline) {
        const diagnostic = await inspectLock(path, binaryPath) ?? { path, classification: 'metadata-unavailable' as const };
        const owner = diagnostic.owner ? ` owner=${JSON.stringify(diagnostic.owner)}` : '';
        throw new Error(`[native-assets] publication-lock-timeout: ${path}; elapsed=${Math.round(performance.now() - started)}ms deadline=${lockWaitMs(env)}ms; ${diagnostic.classification}${owner}. Confirm no OMX hydration process is active for this cache key, remove only this named lock manually, then retry.`);
      }

View on GitHub (pinned to 3ad79a8a6f)