jackwener/OpenCLI · warning
Failed to inspect trace artifact ${dir}: ${err instanceof Er
Error message
Failed to inspect trace artifact ${dir}: ${err instanceof Error ? err.message : String(err)} What it means
While building TraceEntry metadata, readTraceEntries stats each trace directory (createdAt, size, protected flags). If inspection of one directory fails with a non-ENOENT error, this warning is emitted and that directory is skipped from the entries list, but the loop continues for remaining directories.
Source
Thrown at src/observation/retention.ts:169
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)}`);
}
}
}
return entries;
}
function readCreatedAtMs(dir: string, fallbackMs: number): number {
try {
const receipt = JSON.parse(fs.readFileSync(path.join(dir, 'receipt.json'), 'utf-8')) as { createdAt?: unknown };
if (typeof receipt.createdAt === 'string') {
const parsed = Date.parse(receipt.createdAt);
if (Number.isFinite(parsed)) return parsed;
}
} catch {
// Older or hand-edited trace directories may not have a receipt.
}
return fallbackMs;
}View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the retention pass — most cases are a race with deletion and resolve on retry.
- Check permissions on the specific directory (path is included in the message) and fix with chmod/chown.
- Remove or fix broken/cyclic symlinks inside the traces directory.
- Ensure no concurrent process is mutating the traces directory while retention runs (serialize cleanup).
Example fix
// before
directorySize(dir); // throws on unreadable subdir
// after
function safeDirectorySize(dir: string): number {
try { return directorySize(dir); } catch { return 0; }
} Defensive patterns
Strategy: try-catch
Validate before calling
try { fs.accessSync(dir, fs.constants.R_OK); } catch { console.warn(`unreadable trace dir, skipping: ${dir}`); } Type guard
function isStatSafe(dir: string): boolean {
try { return fs.statSync(dir).isDirectory(); } catch { return false; }
} Try / catch
try {
const stat = fs.statSync(dir);
inspect(dir, stat);
} catch (err) {
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') console.warn(`inspect failed ${dir}: ${(err as Error).message}`);
} Prevention
- Avoid concurrent prune + scan over the same traces directory.
- Remove cyclic symlinks from trace output.
- Keep uniform permissions across trace subdirectories.
- Treat missing entries (ENOENT) as normal and retry the pass later.
When it happens
Trigger: The per-entry stat/size walk (readCreatedAtMs, directorySize) throws — e.g. the directory vanished between readdir and stat (ENOENT is silently ignored, others are not), permission denied on a subdirectory during directorySize traversal, or symlink loops causing ELOOP.
Common situations: Another process (or a concurrent prune) deleting trace dirs mid-scan; partially-written traces with restricted subdirectories; symlinked trace dirs pointing outside with no access; ELOOP from cyclic symlinks.
Related errors
- Failed to write Pixiv novel ${path.basename(plan.destPath)}:
- File could not be read: ${path}
- Receipt file cannot be read: ${receipt}
- Browser reported a completed download but the file is missin
- Could not store Midjourney ${kind} at ${filePath}: ${errorMe
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/77d0e6f222378dd7.
Report an issue: GitHub.