{"record":{"id":"3ab52bdb228059cc","repo":"payloadcms/payload","slug":"attachment-content-must-be-a-string-or-a-buffer","errorCode":null,"errorMessage":"Attachment content must be a string or a buffer","messagePattern":"Attachment content must be a string or a buffer","errorType":"validation","errorClass":"APIError","httpStatus":400,"severity":"error","filePath":"packages/email-resend/src/index.ts","lineNumber":182,"sourceCode":"        path,\n      }\n    }\n\n    if (typeof attachment.content === 'string') {\n      return {\n        content: attachment.content,\n        filename: attachment.filename,\n      }\n    }\n\n    if (attachment.content instanceof Buffer) {\n      return {\n        content: attachment.content,\n        filename: attachment.filename,\n      }\n    }\n\n    throw new APIError('Attachment content must be a string or a buffer', 400)\n  })\n}\n\nfunction mapHeaders(headers: SendEmailOptions['headers']): Record<string, string> | undefined {\n  if (!headers) {\n    return undefined\n  }\n\n  // Array-of-objects form: [{ key: string; value: string }, ...]\n  if (Array.isArray(headers)) {\n    return headers.reduce<Record<string, string>>((acc, { key, value }) => {\n      acc[key] = value\n      return acc\n    }, {})\n  }\n\n  // Object form: { [key: string]: string | string[] | { prepared: boolean; value: string } }\n  return Object.entries(headers).reduce<Record<string, string>>((acc, [key, value]) => {","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/email-resend/src/index.ts#L164-L200","documentation":"Thrown by the Resend attachment mapper after it has confirmed the attachment uses the `content` branch (not `path`) but the `content` value is neither a `string` nor a `Buffer`. The mapper checks `typeof === 'string'` first, then `instanceof Buffer`, and falls through to this error for any other type (number, object, array, typed array that is not Buffer, etc.). It is a 400 APIError surfaced from the Payload→Resend transport layer.","triggerScenarios":"Setting `attachment.content` to a non-string/non-Buffer value such as a number, plain object, array, or a Uint8Array/ArrayBuffer (which are NOT instances of Buffer). For example `attachments: [{ filename: 'd.bin', content: new Uint8Array([1,2,3]) }]` triggers it because `Uint8Array` is not `Buffer`.","commonSituations":"Browser-side code or Web Crypto / fetch APIs that return `Uint8Array`/`ArrayBuffer` instead of Node `Buffer`; passing a parsed JSON number/object directly as attachment content; assuming all typed arrays are Buffers; receiving content from a stream and not wrapping it with `Buffer.from()`.","solutions":["Convert the value to a Buffer before attaching: `content: Buffer.from(uint8array)` or `Buffer.from(arrayBuffer)`.","If content is JSON or text, pass it as a string: `content: JSON.stringify(obj)`.","Type the attachment content field strictly as `string | Buffer` in your own call site and enforce it before calling sendEmail."],"exampleFix":"// before\nattachments: [{ filename: 'sig.bin', content: crypto.getRandomValues(new Uint8Array(16)) }]\n\n// after\nattachments: [{ filename: 'sig.bin', content: Buffer.from(crypto.getRandomValues(new Uint8Array(16))) }]","handlingStrategy":"type-guard","validationCode":"function toBufferContent(content) {\n  if (typeof content === 'string') return content\n  if (content instanceof Buffer) return content\n  if (ArrayBuffer.isView(content)) return Buffer.from(content.buffer, content.byteOffset, content.byteLength)\n  if (content instanceof ArrayBuffer) return Buffer.from(content)\n  throw new Error('attachment content must be string or Buffer')\n}","typeGuard":"function isStringOrBuffer(v: unknown): v is string | Buffer {\n  return typeof v === 'string' || Buffer.isBuffer(v)\n}","tryCatchPattern":"try {\n  await payload.sendEmail({ ..., attachments: [{ filename, content: toBufferContent(raw) }] })\n} catch (e) {\n  if (e instanceof APIError && /content must be a string or a buffer/.test(e.message)) {\n    // normalize content before retry\n  }\n  throw e\n}","preventionTips":["Always coerce typed arrays/ArrayBuffers with `Buffer.from(...)` before assigning to attachment.content.","Keep a strict `string | Buffer` type on your own attachment builder.","Unit-test the attachment builder with a Uint8Array input."],"tags":["email","resend","attachments","buffer","type-coercion","validation"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}