{"id":"26031d3bea8701d8","repo":"vitest-dev/vitest","slug":"test-attachment-requires-only-one-of-body-or-pa","errorCode":null,"errorMessage":"Test attachment requires only one of \"body\" or \"path\" to be set. Both are specified.","messagePattern":"Test attachment requires only one of \"body\" or \"path\" to be set\\. Both are specified\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/runner/artifact.ts","lineNumber":175,"sourceCode":"  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":157,"sourceCodeEnd":188,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/runtime/runner/artifact.ts#L157-L188","documentation":"An attachment must specify exactly ONE payload source — `body` (inline) or `path` (file reference) — not both. `manageArtifactAttachment` (`artifact.ts:175`) rejects attachments carrying both as a `TypeError`, because the reporter wouldn't know which to serialize and the two could conflict.","triggerScenarios":"`recordArtifact(task, { type: '...', attachments: [{ body: 'data', path: '/tmp/f' }] })`; a builder that defensively sets every field.","commonSituations":"Copy-paste from an example/template that had both fields; a 'set everything' defensive pattern; merging two attachment configs.","solutions":["Keep only `body` for inline content, or only `path` for a file reference.","If you have both a file and inline bytes, pick one — usually `path` is cheaper for large content.","Validate attachments before calling `recordArtifact` (see validationCode)."],"exampleFix":"// before\nrecordArtifact(task, {\n  type: 'report',\n  attachments: [{ name: 'out', body: 'data', path: '/tmp/f' }],\n})\n\n// after — pick one\nrecordArtifact(task, {\n  type: 'report',\n  attachments: [{ name: 'out', body: 'data' }],\n})","handlingStrategy":"validation","validationCode":"// Ensure body and path are mutually exclusive.\nfunction validateAttachments(attachments: TestAttachment[]) {\n  for (const a of attachments) {\n    if (a.body != null && a.path) {\n      throw new TypeError(`Attachment \"${a.name ?? '<unnamed>'}\" has both body and path`)\n    }\n  }\n}\nvalidateAttachments(artifact.attachments ?? [])\nawait recordArtifact(task, artifact)","typeGuard":"function hasExclusivePayload(a: { body?: unknown; path?: string }): boolean {\n  const hasBody = a.body != null\n  const hasPath = Boolean(a.path)\n  return (hasBody || hasPath) && !(hasBody && hasPath)\n}","tryCatchPattern":"try {\n  await recordArtifact(task, artifact)\n} catch (e) {\n  if (e instanceof TypeError && /only one of \"body\" or \"path\"/.test(e.message)) {\n    // drop one of body/path and retry\n  } else throw e\n}","preventionTips":["Choose ONE payload source per attachment — body for inline, path for files.","For large content, prefer path to avoid bloating the serialized artifact.","Validate the body/path exclusivity in a builder before calling recordArtifact."],"tags":["artifacts","attachment","validation","typeerror"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}