koala73/worldmonitor · error · TypeError

Unsupported physical divergence metal: ${String(reading?.met

Error message

Unsupported physical divergence metal: ${String(reading?.metal)}

What it means

buildPhysicalStressComposite validates each reading's metal against METAL_ORDER (the closed set ['gold','silver']); any other metal (or missing metal on null/undefined readings) throws this TypeError. The composite is defined only over the contract's metals.

Source

Thrown at shared/physical-divergence-contract.js:134

}

export function isPhysicalDivergenceStoredReadingReason(state, reason) {
  return STORED_READING_REASONS_BY_STATE[state]?.includes(reason) === true;
}

export function isPhysicalDivergenceStoredCompositeReason(state, reason) {
  if (state === 'ok') return reason === '';
  return NON_OK_STATE_PRIORITY.includes(state)
    && COMPOSITE_MEMBER_REASONS.includes(reason)
    && reason.endsWith(`:${state}`);
}

export function buildPhysicalStressComposite(readings) {
  const values = Array.isArray(readings) ? readings : [];
  const byMetal = new Map();
  for (const reading of values) {
    if (!METAL_ORDER.includes(reading?.metal)) {
      throw new TypeError(`Unsupported physical divergence metal: ${String(reading?.metal)}`);
    }
    if (byMetal.has(reading.metal)) {
      throw new TypeError(`Physical divergence composite repeats a metal: ${reading.metal}`);
    }
    if (!STATES.includes(reading.state)) {
      throw new TypeError(`Unknown physical divergence state: ${String(reading.state)}`);
    }
    byMetal.set(reading.metal, reading);
  }
  const weights = METAL_ORDER.map((metal) => ({
    metal,
    weight: PHYSICAL_DIVERGENCE_CONTRACT.metals[metal].weight,
    methodologyVersion: METHODOLOGY_VERSION,
  }));
  for (const metal of METAL_ORDER) {
    if (!byMetal.has(metal)) {
      return {
        state: 'missing_input',

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Only pass readings whose metal is 'gold' or 'silver'
  2. Filter or reject unsupported metals before building the composite
  3. Normalize upstream symbols (XAU->gold, XAG->silver) first
  4. If a new metal is genuinely needed, add it to METAL_ORDER and PHYSICAL_DIVERGENCE_CONTRACT.metals with a weight

Example fix

// before
buildPhysicalStressComposite([{ metal: 'copper', state: 'ok', index: 1 }])
// after
const supported = readings.filter((r) => ['gold', 'silver'].includes(r?.metal));
buildPhysicalStressComposite(supported)
Defensive patterns

Strategy: type-guard

Validate before calling

import { METAL_ORDER } from './physical-divergence-contract.js';
function filterSupportedReadings(readings) {
  return (Array.isArray(readings) ? readings : []).filter((r) => METAL_ORDER.includes(r?.metal));
}

Type guard

function isSupportedReading(r) {
  return r != null && METAL_ORDER.includes(r.metal) && typeof r.metal === 'string';
}

Try / catch

try {
  composite = buildPhysicalStressComposite(readings);
} catch (e) {
  if (e instanceof TypeError && e.message.startsWith('Unsupported physical divergence metal')) {
    composite = null; // drop and report the unsupported metal
  } else throw e;
}

Prevention

When it happens

Trigger: Passing readings with metals like 'copper', 'platinum', or a typo such as 'golf'; passing null/undefined readings (reading?.metal is undefined); feeding raw market data not normalized to the contract's metal set.

Common situations: Extending the dashboard to new metals without updating the contract; upstream feed using different metal symbols (XAU/XAG); map/filter pipelines that drop or mangle the metal field.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/f11f47eaccb04d73. Report an issue: GitHub.