vitest-dev/vitest · error · TypeError
Test attachment requires only one of "body" or "path" to be…
Error message
Test attachment requires only one of "body" or "path" to be set. Both are specified.
What it means
Thrown by manageArtifactAttachment when a TestAttachment has both a non-null 'body' and a truthy 'path'. Vitest treats attachments as either inline content (body) or a file reference (path); specifying both is ambiguous and would cause double-handling during serialization. The guard runs for every attachment on artifacts passed to recordArtifact and on annotations that carry an attachment.
Solutions
- Pick exactly one source: set `body` for inline content OR `path` for a file/URL, never both.
- If you have both bytes and a file, write the bytes to disk first and keep only `path`, or drop the file and keep only `body`.
- Strip the unused field explicitly before constructing the attachment: `const { body, ...rest } = source; attach({ ...rest, body })`.
- Add a unit test asserting your attachment factory never emits both keys.
Example fix
// before
await ctx.annotate('screenshot', {
path: '/tmp/shot.png',
body: pngBytes,
})
// after (inline)
await ctx.annotate('screenshot', { body: pngBytes })
// after (file)
await ctx.annotate('screenshot', { path: '/tmp/shot.png' }) Defensive patterns
Strategy: validation
Validate before calling
function assertAttachment(a: Partial<TestAttachment>) {
if (a.body != null && a.path) {
throw new Error('Attachment has both body and path; pick one.')
}
}
// call before context.annotate / recordArtifact Type guard
const isBodyOnly = (a: TestAttachment) => a.body != null && !a.path const isPathOnly = (a: TestAttachment) => !!a.path && a.body == null
Try / catch
try {
await ctx.annotate(msg, attachment)
} catch (e) {
if (e instanceof TypeError && /both are specified/i.test(e.message)) {
// strip one field and retry, or log
} else throw e
} Prevention
- Use a single attach() helper in your codebase that enforces one of body/path.
- Never spread shared attachment templates that pre-set both fields.
- Add an eslint rule or unit test asserting your factory output.
When it happens
Trigger: Calling context.annotate(message, attachment) or recordArtifact(task, { attachments: [...] }) where a single attachment object sets both `body` (string/Uint8Array) and `path` (string). Also triggered by custom reporters/plugins that construct TestAttachment objects with both fields populated.
Common situations: Copying an attachment object literal that defaulted path and then assigning body; building attachments from a generic helper that always sets path and lets the caller override body; migrating from a reporter that stored both raw bytes and a temp file path.
Related errors
- Test attachment with "path" should not have "bodyEncoding"…
- Cannot annotate tests outside of the test run. The test
- Test attachment requires "body" or "path" to be set. Both…
- All browser instances within a project must use the same…
- `bench.compare()` expects every argument to be the return…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/26031d3bea8701d8.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/runtime/runner/artifact.ts:175
return promise
}
/**
* Validates and prepares a test attachment for serialization.
*
* This function ensures attachments have either `body` or `path` set (but not both), and converts `Uint8Array` bodies to base64-encoded strings for easier serialization.
*
* @param attachment - The attachment to validate and prepare
*
* @throws {TypeError} If neither `body` nor `path` is provided
* @throws {TypeError} If both `body` and `path` are provided
*/
export function manageArtifactAttachment(attachment: TestAttachment): void {
if (attachment.body == null && !attachment.path) {
throw new TypeError(`Test attachment requires "body" or "path" to be set. Both are missing.`)
}
if (attachment.body && attachment.path) {
throw new TypeError(`Test attachment requires only one of "body" or "path" to be set. Both are specified.`)
}
if (attachment.path && attachment.bodyEncoding) {
throw new TypeError(`Test attachment with "path" should not have "bodyEncoding" specified.`)
}
// convert to a string so it's easier to serialise
if (attachment.body instanceof Uint8Array) {
attachment.body = encodeUint8Array(attachment.body)
}
if (attachment.body != null) {
attachment.bodyEncoding ??= 'base64'
}
}
View on GitHub (pinned to 1fa9837ec2)