vitest-dev/vitest · error · TypeError
Expected string coverage payload, received ${typeof coverage
Error message
Expected string coverage payload, received ${typeof coverage}, ${JSON.stringify(coverage)} What it means
BlobReporter.onAfterSuiteRun (coverage.ts:293) requires the worker's coverage payload to be a string — the path to the coverage file the worker wrote. A non-string (object, etc.) means the IPC/transport contract is broken; vitest won't try to interpret arbitrary coverage objects here.
Source
Thrown at packages/vitest/src/node/coverage.ts:293
await fs.rm(this.coverageFilesDirectory, {
recursive: true,
force: true,
maxRetries: 10,
})
}
await fs.mkdir(this.coverageFilesDirectory, { recursive: true })
this.coverageFiles = new Map()
}
onAfterSuiteRun({ coverage, environment, projectName, testFiles }: AfterSuiteRunMeta): void {
if (!coverage) {
return
}
if (typeof coverage !== 'string') {
throw new TypeError(`Expected string coverage payload, received ${typeof coverage}, ${JSON.stringify(coverage)}`)
}
const filename = coverage
let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT)
if (!entry) {
entry = {}
this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry)
}
const testFilenames = testFiles.join()
entry[environment] ??= {}
// If there's a result from previous run, overwrite it
entry[environment][testFilenames] = filename
}
async readCoverageFiles<CoverageType>({ onFileRead, onFinished, onDebug }: {
/** Callback invoked with a single coverage result */View on GitHub (pinned to d568f8ce37)
Solutions
- Ensure worker code writes coverage to a file and sends only the file path string as coverage.
- Use vitest's standard coverage transport (don't short-circuit onAfterSuiteRun).
- If writing a custom pool, mirror how @vitest/coverage-* workers serialize coverage.
Example fix
// before (custom worker)
child.send({ coverage: coverageJsonObject })
// after
const path = await writeCoverageFile(coverageJsonObject)
child.send({ coverage: path }) Defensive patterns
Strategy: validation
Validate before calling
function assertCoverageString(payload: unknown): asserts payload is string {
if (typeof payload !== 'string') {
throw new TypeError(`coverage must be a file-path string, got ${typeof payload}`)
}
} Type guard
function isCoveragePath(c: unknown): c is string {
return typeof c === 'string' && c.length > 0
} Prevention
- Always serialize coverage to a file in the worker and send only the path.
- Don't bypass vitest's standard coverage transport in custom pools.
- Add a contract test asserting worker messages carry string coverage.
When it happens
Trigger: A custom pool/environment/transport sending coverage as a structured object instead of a file path string; tampered or malformed worker IPC payload reaching onAfterSuiteRun.
Common situations: Custom forks/tinypool implementations that bypass the standard coverage serialization; tests that mock worker messages incorrectly.
Related errors
- Something removed the coverage directory "${coverageFilesDir
- Something removed the coverage directory "${coverageFilesDir
- V8 provider missing inspector session.
- [vitest] Cannot register a mock that is already defined. Exp
- "Istanbul" coverage provider is not compatible with "experim
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/64cf1c411aa87362.json.
Report an issue: GitHub.