jackwener/OpenCLI · warning

Failed to list trace artifacts in ${tracesDir}: ${err instan

Error message

Failed to list trace artifacts in ${tracesDir}: ${err instanceof Error ? err.message : String(err)}

What it means

readTraceEntries lists the traces directory with fs.readdirSync to build retention entries. Any listing error other than ENOENT (missing dir is treated as "no traces") triggers this warning and returns an empty list. The library throws it so callers still get a safe empty result instead of crashing retention.

Source

Thrown at src/observation/retention.ts:151

    scanned: entries.length,
    deleted: deletedDirs,
    kept: keptEntries.map((entry) => entry.dir),
    totalBytesBefore,
    totalBytesAfter: keptEntries.reduce((sum, entry) => sum + entry.sizeBytes, 0),
  };
}

function readTraceEntries(
  tracesDir: string,
  protectedDirs: Set<string>,
  warn: (message: string) => void,
): TraceEntry[] {
  let names: string[];
  try {
    names = fs.readdirSync(tracesDir);
  } catch (err) {
    if (isEnoent(err)) return [];
    warn(`Failed to list trace artifacts in ${tracesDir}: ${err instanceof Error ? err.message : String(err)}`);
    return [];
  }

  const entries: TraceEntry[] = [];
  for (const name of names) {
    const dir = path.join(tracesDir, name);
    try {
      const stat = fs.statSync(dir);
      if (!stat.isDirectory()) continue;
      entries.push({
        dir,
        createdAtMs: readCreatedAtMs(dir, stat.mtimeMs),
        sizeBytes: directorySize(dir),
        protected: protectedDirs.has(path.resolve(dir)),
      });
    } catch (err) {
      if (!isEnoent(err)) {
        warn(`Failed to inspect trace artifact ${dir}: ${err instanceof Error ? err.message : String(err)}`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify tracesDir exists and is a directory (fs.statSync(tracesDir).isDirectory()); fix the configured path if not.
  2. Grant the process user read+execute permission on the traces directory.
  3. If the error is EMFILE/ENFILE, raise the file-descriptor limit (ulimit -n) or reduce concurrent I/O.
  4. Create the directory with mkdirSync(tracesDir, {recursive:true}) if you want an empty result to be legitimate.

Example fix

// before
warn(`Failed to list trace artifacts in ${tracesDir}: ...`);
// after
fs.mkdirSync(tracesDir, { recursive: true }); // ensure dir exists before listing
const stats = fs.statSync(tracesDir);
if (!stats.isDirectory()) throw new Error(`tracesDir is not a directory: ${tracesDir}`);
Defensive patterns

Strategy: fallback

Validate before calling

let ok = true;
try { ok = fs.statSync(tracesDir).isDirectory(); } catch { ok = false; }
if (!ok) fs.mkdirSync(tracesDir, { recursive: true });

Type guard

function isReadableDir(p: string): boolean {
  try {
    const st = fs.statSync(p);
    fs.accessSync(p, fs.constants.R_OK);
    return st.isDirectory();
  } catch { return false; }
}

Try / catch

try {
  names = fs.readdirSync(tracesDir);
} catch (err) {
  if ((err as NodeJS.ErrnoException).code === 'ENOENT') { names = []; }
  else { console.warn(`readdir failed: ${(err as Error).message}`); names = []; }
}

Prevention

When it happens

Trigger: fs.readdirSync(tracesDir) throws for reasons other than the directory not existing: EACCES (no read permission), ENOTDIR (tracesDir path is a file), EIO (disk issue), or EMFILE/ENFILE (too many open files).

Common situations: tracesDir misconfigured to point at a regular file; permissions changed after a container/user switch; ulimit too low producing EMFILE under heavy load; networked filesystem briefly unavailable.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/76bbd591444cf8d8. Report an issue: GitHub.