{"record":{"id":"9f8e48d16bc4252e","repo":"koala73/worldmonitor","slug":"unsupported-metal-unsupported-length-1","errorCode":null,"errorMessage":"Unsupported metal${unsupported.length === 1 ? '' : 's'}: ${unsupported.join(', ')}","messagePattern":"Unsupported metal(.+?): (.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"server/worldmonitor/market/v1/get-physical-premiums.ts","lineNumber":160,"sourceCode":"    || !isoInstant(raw.asOf)\n  ) return null;\n  return { pair: raw.pair, rate: raw.rate, source: raw.source, asOf: raw.asOf };\n}\n\nexport function resolvePhysicalPremiumMetals(rawMetals: string[]): string[] {\n  const metals: string[] = [];\n  const unsupported: string[] = [];\n  for (const raw of rawMetals) {\n    const metal = raw.trim().toLowerCase();\n    if (!metal || !SUPPORTED_METALS.has(metal)) {\n      const label = metal || '<blank>';\n      if (!unsupported.includes(label)) unsupported.push(label);\n      continue;\n    }\n    if (!metals.includes(metal)) metals.push(metal);\n  }\n  if (unsupported.length > 0) {\n    throw new ValidationError([{\n      field: 'metals',\n      description: `Unsupported metal${unsupported.length === 1 ? '' : 's'}: ${unsupported.join(', ')}`,\n    }]);\n  }\n  return metals;\n}\n\nexport async function getPhysicalPremiums(\n  _ctx: ServerContext,\n  req: GetPhysicalPremiumsRequest,\n): Promise<GetPhysicalPremiumsResponse> {\n  const metals = resolvePhysicalPremiumMetals(parseStringArray(req.metals));\n  const read = await readCachedJson(PHYSICAL_PREMIUM_KEY, true);\n  if (read.status === 'error') throw new SeedUnavailableError(PHYSICAL_PREMIUM_KEY);\n  try {\n    const raw = read.status === 'hit' ? read.value as RawPayload | null : null;\n    const fx = mapFx(raw?.fx);\n    if (!fx || !Array.isArray(raw?.premiums)) return { premiums: [] };","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/server/worldmonitor/market/v1/get-physical-premiums.ts#L142-L178","documentation":"Validation in resolvePhysicalPremiumMetals: one or more requested metals (listed in the message) are not in SUPPORTED_METALS after trim and lowercase normalization — including blank entries, reported as '<blank>'. The whole request is rejected rather than silently dropping the unsupported metals.","triggerScenarios":"Thrown at server/worldmonitor/market/v1/get-physical-premiums.ts:159 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Request only supported metals; check the message for the exact unsupported labels","Trim and validate the metals list client-side against the supported set before calling"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"e586b8b4b80f595aa7ece295eec10d76f2921240","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}