{"record":{"id":"b607e45c54783ebc","repo":"vitest-dev/vitest","slug":"test-attachment-requires-body-or-path-to-be-se","errorCode":null,"errorMessage":"Test attachment requires \"body\" or \"path\" to be set. Both are missing.","messagePattern":"Test attachment requires \"body\" or \"path\" to be set\\. Both are missing\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/runner/artifact.ts","lineNumber":172,"sourceCode":"    test.promises = []\n  }\n  test.promises.push(promise)\n  return promise\n}\n\n/**\n * Validates and prepares a test attachment for serialization.\n *\n * This function ensures attachments have either `body` or `path` set (but not both), and converts `Uint8Array` bodies to base64-encoded strings for easier serialization.\n *\n * @param attachment - The attachment to validate and prepare\n *\n * @throws {TypeError} If neither `body` nor `path` is provided\n * @throws {TypeError} If both `body` and `path` are provided\n */\nexport function manageArtifactAttachment(attachment: TestAttachment): void {\n  if (attachment.body == null && !attachment.path) {\n    throw new TypeError(`Test attachment requires \"body\" or \"path\" to be set. Both are missing.`)\n  }\n  if (attachment.body && attachment.path) {\n    throw new TypeError(`Test attachment requires only one of \"body\" or \"path\" to be set. Both are specified.`)\n  }\n  if (attachment.path && attachment.bodyEncoding) {\n    throw new TypeError(`Test attachment with \"path\" should not have \"bodyEncoding\" specified.`)\n  }\n  // convert to a string so it's easier to serialise\n  if (attachment.body instanceof Uint8Array) {\n    attachment.body = encodeUint8Array(attachment.body)\n  }\n  if (attachment.body != null) {\n    attachment.bodyEncoding ??= 'base64'\n  }\n}\n","sourceCodeStart":154,"sourceCodeEnd":188,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/runtime/runner/artifact.ts#L154-L188","documentation":"A `TestAttachment` must carry either `body` (inline content) or `path` (a file reference) — one is required so the reporter/CI consumer has something to render. This `TypeError` fires when both are missing/null. The validation runs in `manageArtifactAttachment`, which `recordArtifact` calls for every entry in `artifact.attachments`.","triggerScenarios":"Passing `recordArtifact(task, { type: '...', attachments: [{ name: 'log' /* no body, no path */ }] })`; an attachment built dynamically where both fields ended up undefined; destructuring an attachment from an API response that omits both fields. The guard is `attachment.body == null && !attachment.path` at artifact.ts:171.","commonSituations":"Building attachments from optional/conditional data where neither branch populated a field; refactoring that renamed `content` to `body` but missed call sites; CI uploading an empty attachment stub; passing `body: ''` is allowed (only null/undefined trigger), but `body: null` is not.","solutions":["Set `body` (string or Uint8Array) for inline content: `attachments: [{ name: 'log', body: '...' }]`.","Or set `path` to a file path: `attachments: [{ name: 'screenshot', path: '/tmp/shot.png' }]`.","When building attachments dynamically, default to an empty string body if you have no path: `body: data ?? ''`.","Filter out empty attachments before recording if neither field is meaningful."],"exampleFix":"// before\nrecordArtifact(task, {\n  type: 'report',\n  attachments: [{ name: 'log' }],\n})\n\n// after\nrecordArtifact(task, {\n  type: 'report',\n  attachments: [{ name: 'log', body: logText }],\n})","handlingStrategy":"validation","validationCode":"for (const a of attachments) { if (a.body == null && !a.path) throw new TypeError(`attachment '${a.name}' needs body or path`) }","typeGuard":"function hasBodyOrPath(a: TestAttachment): boolean { return a.body != null || Boolean(a.path) }","tryCatchPattern":"null","preventionTips":["Always set `body` (string/Uint8Array) or `path` on every attachment.","Default to `body: ''` when content is conditionally empty.","Add a pre-flight validation loop over `attachments` before `recordArtifact`.","Remember `body: null` triggers the error; only `string`/`Uint8Array` (or omit for `path`) is valid."],"tags":["artifacts","attachments","validation","type-error"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}