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 scan-project.mjs main() immediately after writeFileSync(outputPath, ...) followed by existsSync(outputPath). The third instance of the defensive write-then-verify pattern (also in extract-import-map and extract-structure). Guards against filesystems where a returned-without-error write is not yet observable by stat.

Source

Thrown at understand-anything-plugin/skills/understand/scan-project.mjs:868

  const output = {
    scriptCompleted: true,
    contentDigest,
    files: fileEntries,
    totalFiles: fileEntries.length,
    filteredByIgnore,
    estimatedComplexity,
    stats: {
      filesScanned: fileEntries.length,
      byCategory,
      byLanguage,
    },
  };

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

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

  process.stderr.write(
    `scan-project: filesScanned=${fileEntries.length} ` +
    `filteredByIgnore=${filteredByIgnore} ` +
    `complexity=${estimatedComplexity}\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. Put outputPath on a local writable filesystem.
  2. Check free space and inode quota on the target volume.
  3. Retry; on reproduction, capture fs.statSync errno and realpathSync(dirname(outputPath)).
  4. Use a tmpfs/scratch directory for outputPath.
Defensive patterns

Strategy: retry

Validate before calling

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

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 {}
    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(outputPath) returns false. Network/overlay/fuse mounts with metadata caching, sandboxed agent runtimes intercepting fs, or quota/inode exhaustion on certain drivers.

Common situations: Agent sandbox runtime intercepting writes. outputPath on NFS/share with deferred visibility. Disk-full or out-of-inodes between write and stat. Path crossing a mount boundary. Concurrent process removing the file in the window between write and stat.

Related errors


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