n8n-io/n8n · error · Error
Snapshot not found: ${filename} (tried ${filePath})
Error message
Snapshot not found: ${filename} (tried ${filePath}) What it means
Plain `Error('Snapshot not found: <filename> (tried <filePath>)')` thrown at e2e.controller.ts:423 when the resolved heap-snapshot file path (from `heapSnapshotPaths` map or `path.resolve(filename)` in cwd) does not exist via `fs.existsSync`. Test-only controller; serialized as a 500 by the generic handler. The message leaks the absolute path tried.
Source
Thrown at packages/cli/src/controllers/e2e.controller.ts:423
/**
* Download a heap snapshot file as a stream.
* The response-helper pipes Readable streams directly to the response.
*/
@Get('/heap-snapshot/:filename', { skipAuth: true })
downloadHeapSnapshot(req: Request) {
const fs = require('node:fs') as typeof nodeFs;
const path = require('node:path') as typeof nodePath;
const filename = path.basename(req.params.filename);
if (!filename.endsWith('.heapsnapshot')) {
throw new Error('Invalid file type');
}
// Look up the full path stored during POST, or try cwd
const filePath = this.heapSnapshotPaths.get(filename) ?? path.resolve(filename);
if (!fs.existsSync(filePath)) {
throw new Error(`Snapshot not found: ${filename} (tried ${filePath})`);
}
return fs.createReadStream(filePath);
}
// --- Per-spec backend V8 coverage (DEVP-370) -----------------------------
// Lets the Playwright coverage fixture attribute this main process's V8
// coverage to the spec that produced it, so backend source files land in the
// E2E impact map (today the map is frontend-only). Test-only: the whole
// controller hard-exits outside E2E (see top of file).
//
// Uses `Profiler.getBestEffortCoverage` (NON-draining) + a server-side
// baseline/delta so it never resets the global V8 counters — the shard-level
// `NODE_V8_COVERAGE` exit dump (the Codecov report path) is left untouched.
//
// REQUIRES the coverage run to be single-worker (it is — coverage project
// runs `--workers=1`). Precise coverage is process-global, so the start→take
// window is only attributable to one spec when specs don't run concurrently.View on GitHub (pinned to 5ac6606e81)
Solutions
- Ensure the POST `/e2e/heap-snapshot` route ran and registered the filename in `heapSnapshotPaths` before GET.
- Use the exact filename returned by POST — do not synthesize one.
- Disable any cleanup that removes `.heapsnapshot` files mid-test-run.
- Run the test from the same working directory as the controller process.
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from 'node:fs';
function snapshotReady(p: string) { return existsSync(p); }
// in the test: assert snapshotReady(filePath) before GET Prevention
- Order Playwright specs: POST heap-snapshot must complete before GET.
- Run GET from the same cwd as the controller, or use the exact stored filename.
- Disable mid-run cleanup that removes .heapsnapshot files.
When it happens
Trigger: In E2E mode: requesting a `.heapsnapshot` filename that was never recorded by the POST route, was already cleaned up, or whose file lives outside the resolved base path. The map lookup falls back to cwd, so a relative-name mismatch also triggers it.
Common situations: Playwright run ordering (download before POST completed); temp-file cleanup between runs; running the GET from a different cwd than the POST; fixture using a fabricated filename.
Related errors
- Invalid file type
- File not found: ${path}
- Role not found
- Workflow "${workflowId}" not found.
- Version "${versionIdToPublish}" not found for workflow "${wo
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/f3f2ce2eeb4afb1c.
Report an issue: GitHub.