{"record":{"id":"bbbd81df2966fe37","repo":"mastra-ai/mastra","slug":"if-the-attachment-is-not-an-image-it-must-specify","errorCode":null,"errorMessage":"If the attachment is not an image, it must specify a content type","messagePattern":"If the attachment is not an image, it must specify a content type","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/agent/message-list/prompt/attachments-to-parts.ts","lineNumber":54,"sourceCode":"\n    let url;\n    try {\n      url = new URL(urlString);\n    } catch {\n      throw new Error(`Invalid URL: ${attachment.url}`);\n    }\n\n    switch (url.protocol) {\n      case 'http:':\n      case 'https:':\n      // Cloud storage protocols supported by AI providers (e.g., Vertex AI for gs://, Bedrock for s3://)\n      case 'gs:':\n      case 's3:': {\n        if (attachment.contentType?.startsWith('image/')) {\n          parts.push({ type: 'image', image: url.toString(), mimeType: attachment.contentType });\n        } else {\n          if (!attachment.contentType) {\n            throw new Error('If the attachment is not an image, it must specify a content type');\n          }\n\n          parts.push({\n            type: 'file',\n            data: url.toString(),\n            mimeType: attachment.contentType,\n          });\n        }\n        break;\n      }\n\n      case 'data:': {\n        if (attachment.contentType?.startsWith('image/')) {\n          parts.push({\n            type: 'image',\n            image: urlString,\n            mimeType: attachment.contentType,\n          });","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/agent/message-list/prompt/attachments-to-parts.ts#L36-L72","documentation":"For remote (http/https/gs/s3/data-protocol family) attachments that are not images, attachmentsToParts emits a 'file' part that requires a mimeType. If attachment.contentType is missing (and the attachment isn't an image), the function throws because the downstream provider file part has no way to interpret the data.","triggerScenarios":"Adding a user message with a cloud/HTTP attachment (gs://, s3://, http(s)://) that has no contentType and is not image/* — e.g. { url: 's3://bucket/report.pdf' } with no contentType field.","commonSituations":"Custom upload pipelines that don't persist MIME type; S3/Vertex references built manually without metadata; UIs that only capture the file name/URL.","solutions":["Set contentType on the attachment (e.g. 'application/pdf') when constructing it.","Derive the MIME type from the file extension or the storage object's metadata before adding the message.","If the source is a browser upload, use the File object's native type property.","Return an explicit validation error in your app layer when contentType is absent so users get a clearer message."],"exampleFix":"// before\n{ url: 'gs://bucket/doc.pdf' }\n// after\n{ url: 'gs://bucket/doc.pdf', contentType: 'application/pdf' }","handlingStrategy":"validation","validationCode":"function assertRemoteAttachment(a: { url: string; contentType?: string }) {\n  const protocol = new URL(a.url).protocol;\n  if (['http:', 'https:', 'gs:', 's3:'].includes(protocol) && !a.contentType) {\n    throw new Error(`Attachment ${a.url} needs a contentType`);\n  }\n}","typeGuard":"function hasContentType(a: { contentType?: string }): a is { contentType: string } {\n  return typeof a.contentType === 'string' && a.contentType.length > 0;\n}","tryCatchPattern":"try {\n  messageList.add(toUserContent(attachment));\n} catch (e) {\n  if (e instanceof Error && e.message.includes('must specify a content type')) {\n    attachment.contentType = lookupMimeFromExtension(attachment.url) ?? 'application/octet-stream';\n    messageList.add(toUserContent(attachment));\n  } else throw e;\n}","preventionTips":["Always persist and pass contentType from the original upload.","Derive MIME from file extension server-side as a fallback.","Return a 400 to clients that submit non-image attachments without a MIME type."],"tags":["attachment","mime-type","validation"],"backgroundTag":"missing-content-type","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}