{"record":{"id":"9246386599736b7d","repo":"transloadit/uppy","slug":"metadata-must-be-an-object","errorCode":null,"errorMessage":"metadata must be an object","messagePattern":"metadata must be an object","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"packages/@uppy/companion/src/server/Uploader.ts","lineNumber":132,"sourceCode":"\n    const method = options.httpMethod.toUpperCase()\n    if (method !== 'PUT' && method !== 'POST') {\n      throw new ValidationError('unsupported HTTP METHOD specified')\n    }\n  }\n\n  if (exceedsMaxFileSize(options.companionOptions.maxFileSize, options.size)) {\n    throw new ValidationError('maxFileSize exceeded')\n  }\n\n  // validate fieldname (optional)\n  if (options.fieldname != null && typeof options.fieldname !== 'string') {\n    throw new ValidationError('fieldname must be a string')\n  }\n\n  // validate metadata (optional)\n  if (options.metadata != null && typeof options.metadata !== 'object') {\n    throw new ValidationError('metadata must be an object')\n  }\n\n  // validate headers (optional)\n  if (options.headers != null && typeof options.headers !== 'object') {\n    throw new ValidationError('headers must be an object')\n  }\n\n  // validate protocol (optional)\n  if (\n    options.protocol &&\n    !Object.values(PROTOCOLS).includes(options.protocol)\n  ) {\n    throw new ValidationError('unsupported protocol specified')\n  }\n\n  // s3 uploads don't require upload destination\n  // validation, because the destination is determined\n  // by the server's s3 config","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/companion/src/server/Uploader.ts#L114-L150","documentation":"The optional metadata option must be a plain object when provided; anything else (string, number, array treated loosely, etc.) throws a ValidationError before upload starts.","triggerScenarios":"new Uploader({ metadata: 'string' }) or metadata: 42 — any non-object value.","commonSituations":"Passing JSON-encoded metadata strings from the client without parsing; Uppy metadata not being forwarded as an object through custom integrations.","solutions":["Pass metadata as an object: metadata: { foo: 'bar' }","JSON.parse metadata strings received from clients before constructing Uploader","Omit metadata if none is needed"],"exampleFix":"// before\nmetadata: req.body.metadata // '{\"foo\":\"bar\"}'\n\n// after\nmetadata: typeof req.body.metadata === 'string' ? JSON.parse(req.body.metadata) : req.body.metadata","handlingStrategy":"type-guard","validationCode":"if (typeof metadata === 'string') metadata = JSON.parse(metadata)","typeGuard":"const isMetadataObject = (m: unknown): m is Record<string, unknown> => m == null || (typeof m === 'object' && !Array.isArray(m))","tryCatchPattern":"null","preventionTips":["JSON.parse serialized metadata from clients","Validate object shape before constructing Uploader"],"tags":["companion","uploader","validation","metadata"],"backgroundTag":"invalid-option-type","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}