{"record":{"id":"92253261bb0a5f33","repo":"koala73/worldmonitor","slug":"ok-physical-divergence-reading-has-an-invalid-inde","errorCode":null,"errorMessage":"Ok physical divergence reading has an invalid index: ${metal}","messagePattern":"Ok physical divergence reading has an invalid index: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"shared/physical-divergence-contract.js","lineNumber":175,"sourceCode":"      };\n    }\n  }\n  for (const state of NON_OK_STATE_PRIORITY) {\n    for (const metal of METAL_ORDER) {\n      if (byMetal.get(metal).state === state) {\n        return {\n          state,\n          reason: `member_not_ok:${metal}:${state}`,\n          index: null,\n          weights,\n          methodologyVersion: METHODOLOGY_VERSION,\n        };\n      }\n    }\n  }\n  for (const metal of METAL_ORDER) {\n    if (!Number.isFinite(byMetal.get(metal).index)) {\n      throw new TypeError(`Ok physical divergence reading has an invalid index: ${metal}`);\n    }\n  }\n  const index = METAL_ORDER.reduce((sum, metal) => (\n    sum + byMetal.get(metal).index * PHYSICAL_DIVERGENCE_CONTRACT.metals[metal].weight\n  ), 0);\n  return {\n    state: 'ok',\n    reason: '',\n    index: Math.round((index + Number.EPSILON) * 100) / 100,\n    weights,\n    methodologyVersion: METHODOLOGY_VERSION,\n  };\n}\n","sourceCodeStart":157,"sourceCodeEnd":189,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/shared/physical-divergence-contract.js#L157-L189","documentation":"After collecting readings, buildPhysicalStressComposite requires every metal's reading to have a finite numeric index (Number.isFinite), because the composite is a weighted sum of indexes. A missing, null, NaN, or non-numeric index on an 'ok'-labeled path throws this TypeError naming the offending metal.","triggerScenarios":"Passing { metal:'gold', state:'ok' } with no index, index: NaN (e.g. from parseFloat of an empty string), index as a string ('1.2'), or null from a failed computation.","commonSituations":"Upstream feed gaps producing NaN; JSON deserialization turning numbers into strings; division producing NaN when a denominator is zero; forgot-to-set index after computing a normalized score.","solutions":["Ensure every reading has a finite numeric index before the call","Coerce/validate: Number.isFinite(Number(reading.index)) and reject or default otherwise","Fix upstream computation that yields NaN (check for empty series, divide-by-zero)","Skip or downstate such readings (use a non-'ok' state like 'missing_input') instead of including them"],"exampleFix":"// before\nbuildPhysicalStressComposite([{ metal: 'gold', state: 'ok', index: NaN }])\n// after\nconst idx = Number(rawIndex);\nconst reading = Number.isFinite(idx)\n  ? { metal: 'gold', state: 'ok', index: idx }\n  : { metal: 'gold', state: 'missing_input' };","handlingStrategy":"validation","validationCode":"function hasFiniteIndexes(readings) {\n  return (Array.isArray(readings) ? readings : [])\n    .filter((r) => r?.state === 'ok')\n    .every((r) => Number.isFinite(r.index));\n}","typeGuard":"function hasFiniteIndex(r) {\n  return r != null && Number.isFinite(r.index);\n}","tryCatchPattern":"try {\n  composite = buildPhysicalStressComposite(readings);\n} catch (e) {\n  if (e instanceof TypeError && e.message.startsWith('Ok physical divergence reading has an invalid index')) {\n    const metal = e.message.split(': ')[1];\n    // drop or downgrade the offending metal's reading\n  } else throw e;\n}","preventionTips":["Validate Number.isFinite(index) whenever constructing readings","Guard upstream math against NaN (empty series, divide-by-zero)","Never pass string indexes; coerce with Number() first","Represent missing data with a non-'ok' state instead of a NaN index"],"tags":["contract","typeerror","nan","data-quality"],"backgroundTag":"invalid-numeric-input","analyzedSha":"9361220cc013571781071f0206e4d80fd14b2f7f","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}