Egonex-AI/Understand-Anything · error · Error

output file missing after write: ${outputPath}

Error message

output file missing after write: ${outputPath}

What it means

Thrown by extract-import-map.mjs immediately after writeFileSync(outputPath, ...) followed by existsSync(outputPath). The write call returned without throwing, yet the file is not present — a defensive check for filesystems where a successful write does not guarantee immediate visibility (network filesystems, container bind-mounts with caching, sandboxed FS layers).

Source

Thrown at understand-anything-plugin/skills/understand/extract-import-map.mjs:1954

      filesWithImports += 1;
      totalEdges += resolved.length;
    }
  }

  const output = {
    scriptCompleted: true,
    stats: {
      filesScanned: files.length,
      filesWithImports,
      totalEdges,
    },
    importMap,
  };

  writeFileSync(outputPath, JSON.stringify(output, null, 2), 'utf-8');

  if (!existsSync(outputPath)) {
    throw new Error(`output file missing after write: ${outputPath}`);
  }

  process.stderr.write(
    `extract-import-map: filesScanned=${files.length} ` +
    `filesWithImports=${filesWithImports} totalEdges=${totalEdges}\n`,
  );
}

// ---------------------------------------------------------------------------
// Run only when executed directly as a CLI; importing the module (e.g. from
// tests) must not trigger main().
//
// Canonicalize both sides through realpathSync. Node ESM resolves
// import.meta.url through symlinks but pathToFileURL(process.argv[1]) preserves
// them, so a raw equality check silently no-ops when the script is invoked via
// a symlinked plugin install path (the default in Claude Code / Copilot CLI
// caches). See GitHub issue #162.
// ---------------------------------------------------------------------------

View on GitHub (pinned to 32944829e7)

Solutions

  1. Confirm outputPath is on a local writable filesystem, not a network/share mount with metadata caching.
  2. Check disk space and inode/quota on the target volume.
  3. Retry the run; if it reproduces, capture fs.statSync right after write to see errno, and try fs.realpathSync(dirname(outputPath)) to confirm the directory still resolves.
  4. Move outputPath to a tmpfs/local directory and have the caller read from there.
Defensive patterns

Strategy: retry

Validate before calling

import { writeFileSync, existsSync, statSync, realpathSync } from 'node:fs';
import { dirname } from 'node:path';
function safeWriteJson(path, value) {
  writeFileSync(path, JSON.stringify(value, null, 2), 'utf-8');
  if (!existsSync(path)) {
    const dir = realpathSync(dirname(path));
    throw new Error(`write invisible at ${path} (dir=${dir}); check mount/space`);
  }
}

Try / catch

async function writeWithRetry(path, value, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try {
      writeFileSync(path, JSON.stringify(value, null, 2), 'utf-8');
      if (existsSync(path)) return;
    } catch (e) { /* fall through to retry on transient fs */ }
    await new Promise((r) => setTimeout(r, 100 * (i + 1)));
  }
  throw new Error(`output file missing after write: ${path}`);
}

Prevention

When it happens

Trigger: writeFileSync completes but existsSync immediately returns false. This happens on NFS / fuse / overlayfs with metadata caching, in some sandbox runtimes that intercept writes, or when outputPath is on a mount that silently drops the file (out-of-space on certain drivers, quota exceeded).

Common situations: Running the worker inside a sandboxed agent runtime that intercepts fs calls. outputPath on a network/share mount with deferred fsync visibility. Disk quota hit between write and stat. A path that crosses a mount boundary so the write and the stat hit different views. Concurrent cleanup that removed the file in the microsecond window.

Related errors


AI-assisted analysis of Egonex-AI/Understand-Anything@32944829e7 (2026-08-12). Data as JSON: /api/errors/389f009b22893dfd. Report an issue: GitHub.