{"record":{"id":"e2524d27badad25f","repo":"koala73/worldmonitor","slug":"field-must-be-a-string","errorCode":null,"errorMessage":"${field} must be a string","messagePattern":"(.+?) must be a string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"shared/company-monitoring-contract.ts","lineNumber":80,"sourceCode":"const FILTER_HASH = /^[a-f0-9]{64}$/;\nconst RFC3339 = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,9})?Z$/;\nconst LOGICAL_ID_PREFIXES = {\n  company: 'cm_company_',\n  claim: 'cm_claim_',\n  event: 'cm_event_',\n  impact: 'cm_impact_',\n  evidence: 'cm_evidence_',\n} as const;\nconst ULID = '[0-9A-HJKMNP-TV-Z]{26}';\n\nconst encoder = new TextEncoder();\n\nfunction utf8Bytes(value: string): number {\n  return encoder.encode(value).byteLength;\n}\n\nfunction assertPlainText(value: unknown, field: string, maxBytes: number): string {\n  if (typeof value !== 'string') throw new Error(`${field} must be a string`);\n  const unicodeNormalized = value.normalize('NFC');\n  if (CONTROL_CHARACTERS.test(unicodeNormalized)) throw new Error(`${field} contains control characters`);\n  const normalized = unicodeNormalized.trim().replace(/\\s+/g, ' ');\n  if (!normalized) throw new Error(`${field} is required`);\n  if (utf8Bytes(normalized) > maxBytes) throw new Error(`${field} exceeds ${maxBytes} bytes`);\n  return normalized;\n}\n\nfunction normalizeOptionalText(value: unknown, field: string, maxBytes: number): string | undefined {\n  if (value === undefined || value === null || value === '') return undefined;\n  return assertPlainText(value, field, maxBytes);\n}\n\nfunction normalizeList(\n  value: unknown,\n  field: string,\n  maxItems: number,\n  normalize: (item: unknown, index: number) => string,","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/koala73/worldmonitor/blob/eeab0a219fce0f02a00603b532dbae9041b934ac/shared/company-monitoring-contract.ts#L62-L98","documentation":"Contract validation error from assertPlainText in the shared company-monitoring contract: a text field expected to be a string is some other type (number, object, array, null). The offending field name is interpolated into the message. This is a caller-supplied payload bug, caught before any persistence.","triggerScenarios":"Thrown at shared/company-monitoring-contract.ts:80 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Send the named field as a JSON string, not a number, object, or array","Check for client-side serialization mistakes (e.g. forgetting to stringify an identifier)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"eeab0a219fce0f02a00603b532dbae9041b934ac","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}