{"record":{"id":"c58dec5cc5d8a6fd","repo":"mastra-ai/mastra","slug":"metadata-avatarurl-must-be-a-string","errorCode":null,"errorMessage":"metadata.avatarUrl must be a string","messagePattern":"metadata\\.avatarUrl must be a string","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"packages/server/src/server/handlers/validate-avatar.ts","lineNumber":14,"sourceCode":"import { HTTPException } from '../http-exception';\n\nconst AVATAR_MAX_BYTES = 512 * 1024; // 512 KB\n\n/**\n * Validates `metadata.avatarUrl` if present.\n * Ensures it's a well-formed data URL and the decoded payload is ≤ 512 KB.\n * No-ops when metadata is absent or doesn't contain avatarUrl.\n */\nexport function validateMetadataAvatarUrl(metadata: Record<string, unknown> | undefined): void {\n  if (!metadata || !('avatarUrl' in metadata) || metadata.avatarUrl === null || metadata.avatarUrl === undefined)\n    return;\n  if (typeof metadata.avatarUrl !== 'string') {\n    throw new HTTPException(400, { message: 'metadata.avatarUrl must be a string' });\n  }\n\n  const dataUrl = metadata.avatarUrl;\n  const match = dataUrl.match(/^data:([^;]+);base64,(.+)$/);\n  if (!match) {\n    throw new HTTPException(400, {\n      message: 'metadata.avatarUrl must be a valid data URL (data:<mime>;base64,<data>)',\n    });\n  }\n\n  // `Buffer.from(..., 'base64')` decodes leniently — it silently ignores\n  // invalid characters and never throws. Validate the payload format strictly\n  // before measuring its byte length so malformed input is rejected.\n  const base64Payload = match[2]!;\n  const isStrictBase64 =\n    base64Payload.length > 0 &&\n    base64Payload.length % 4 === 0 &&\n    /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(base64Payload);","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/validate-avatar.ts#L1-L32","documentation":"HTTP 400 from validateMetadataAvatarUrl: when metadata contains an avatarUrl key, its value must be a string. Null/undefined are tolerated (treated as absent), but any non-string type (number, object, boolean) is rejected on agent create/update.","triggerScenarios":"POST/PUT to CREATE_STORED_AGENT_ROUTE or UPDATE_STORED_AGENT_ROUTE with metadata like { avatarUrl: 123 } or { avatarUrl: { url: '...' } }.","commonSituations":"Client-side forms sending numbers/null after JSON coercion; scripts assigning the result of a size calculation to avatarUrl; missing client-side schema validation on the metadata object.","solutions":["Send avatarUrl as a base64 data URL string (data:<mime>;base64,<data>).","Omit the avatarUrl key entirely if no avatar is intended.","Add client-side type validation that avatarUrl is a string before submitting."],"exampleFix":"// before\nmetadata: { avatarUrl: 42 }\n// after\nmetadata: { avatarUrl: 'data:image/png;base64,iVBORw0KGgo...' }","handlingStrategy":"type-guard","validationCode":"if (metadata && 'avatarUrl' in metadata && metadata.avatarUrl != null && typeof metadata.avatarUrl !== 'string') {\n  throw new Error('avatarUrl must be a string data URL');\n}","typeGuard":"function isValidAvatarUrl(v: unknown): v is string {\n  return typeof v === 'string';\n}","tryCatchPattern":"try {\n  await saveAgent({ metadata });\n} catch (e) {\n  if (e instanceof HTTPException && e.status === 400 && e.message.includes('avatarUrl must be a string')) {\n    fixAvatarType(metadata);\n  } else throw e;\n}","preventionTips":["Type metadata.avatarUrl as string | null | undefined in client schemas.","Validate payloads with zod before submitting agent create/update requests.","Normalize form inputs to strings or null before sending."],"tags":["http-400","type-mismatch","metadata","validation"],"backgroundTag":"type-validation-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}