{"record":{"id":"563af99015d5291b","repo":"mastra-ai/mastra","slug":"metadata-filter-must-be-an-object","errorCode":null,"errorMessage":"Metadata filter must be an object.","messagePattern":"Metadata filter must be an object\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/utils.ts","lineNumber":106,"sourceCode":"      return JSON.parse(input);\n    } catch {\n      return input;\n    }\n  }\n  // For anything else (number, boolean, etc.), return empty object\n  return {};\n}\n\nconst SAFE_METADATA_KEY_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\nconst MAX_METADATA_KEY_LENGTH = 128;\nconst DISALLOWED_METADATA_KEYS = new Set(['__proto__', 'prototype', 'constructor']);\n\nexport function validateStorageMetadataFilter(\n  metadata: StorageMetadataFilter | undefined,\n): StorageMetadataFilter | undefined {\n  if (metadata === undefined) return undefined;\n  if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) {\n    throw new TypeError('Metadata filter must be an object.');\n  }\n\n  const entries = Object.entries(metadata);\n  for (const [key, value] of entries) {\n    if (\n      key.length > MAX_METADATA_KEY_LENGTH ||\n      !SAFE_METADATA_KEY_PATTERN.test(key) ||\n      DISALLOWED_METADATA_KEYS.has(key)\n    ) {\n      throw new TypeError(`Invalid metadata filter key \"${key}\".`);\n    }\n    if (\n      value !== null &&\n      typeof value !== 'string' &&\n      typeof value !== 'boolean' &&\n      !(typeof value === 'number' && Number.isFinite(value))\n    ) {\n      throw new TypeError(","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/utils.ts#L88-L124","documentation":"validateStorageMetadataFilter requires the metadata filter to be a plain object (not undefined, null, an array, or a primitive). Metadata filters are key/value maps used to filter records in storage; anything else cannot be interpreted as a filter map, so a TypeError is thrown before hitting storage.","triggerScenarios":"Calling metadataFilter(null), metadataFilter([]) (an array is an object but rejected), or metadataFilter('region=us') — any non-plain-object value passed where a metadata filter is expected (e.g. in storage list/query APIs).","commonSituations":"Spreading optional params into a query and passing a variable that ended up null after JSON parsing; accidentally passing an array of key/value pairs instead of an object; string-encoded filters from URL query params not being parsed.","solutions":["Pass a plain object like { region: 'us', env: 'prod' }","Convert arrays of pairs: Object.fromEntries([['region','us']])","Parse string filters from query params with JSON.parse or your own parser before calling","Guard: if (filter && !Array.isArray(filter)) before calling"],"exampleFix":"// before\nstorage.listTraces({ metadata: 'tenant=acme' });\n// after\nstorage.listTraces({ metadata: { tenant: 'acme' } });","handlingStrategy":"validation","validationCode":"function isPlainObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\nconst filter = isPlainObject(rawFilter) ? rawFilter : {};","typeGuard":"function isMetadataFilter(v: unknown): v is Record<string, string | number | boolean | null> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  return await storage.listTraces({ metadata: filter });\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('Metadata filter')) {\n    logger.warn('Dropping invalid metadata filter', { filter });\n    return await storage.listTraces({});\n  }\n  throw e;\n}","preventionTips":["Validate/parse filters from user input (URL params, JSON) before passing them","Never pass arrays as filters; use Object.fromEntries for pair lists","Coerce null to undefined at the boundary if 'no filter' is intended","Add unit tests covering filter parsing from all your input sources"],"tags":["validation","storage","metadata"],"backgroundTag":"metadata-filter-invalid","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}