{"record":{"id":"8e7e0ed962d59cf2","repo":"Hmbown/CodeWhale","slug":"invalid-field-object-required","errorCode":null,"errorMessage":"Invalid ${field}: object required.","messagePattern":"Invalid (.+?): object required\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/core/evidence.ts","lineNumber":64,"sourceCode":"  id: string; code: string; severity: 'info'|'warning'|'critical';\n  title: string; detail: string; recordIds: string[]; time: number;\n}\nexport interface Interaction {\n  runId: string; sandboxId?: string; group?: string; target: string;\n  kind: string; stage: Stage; effect: Effect; count: number; recordIds: string[];\n}\nexport interface BoundaryAnalysis {\n  version: 1; omittedFindings: number; asOf: number; inputRecords: number; visibleRecords: number; uniqueRecords: number;\n  futureRecords: number; findings: BoundaryFinding[]; coverage: CoverageRow[];\n  interactions: Interaction[]; runs: number; sandboxes: number; externalEffects: number;\n  unknownEffects: number; authority: { permitted: number; denied: number; unknown: number };\n  provenance: string;\n}\nconst enumValue = <T extends string>(v:unknown, values: readonly T[], field:string): T => {\n  if(typeof v!=='string'||!values.includes(v as T))throw new Error(`Invalid ${field}.`);return v as T;\n};\nconst object = (v:unknown, field:string): Record<string,unknown> => {\n  if(!v||typeof v!=='object'||Array.isArray(v))throw new Error(`Invalid ${field}: object required.`);return v as Record<string,unknown>;\n};\nconst text = (v:unknown, field:string, max=256):string => {\n  if(typeof v!=='string'||!v.length||v.length>max||/[\\u0000-\\u001f\\u007f]/.test(v))throw new Error(`Invalid ${field}: nonempty bounded text required.`);return v;\n};\nconst num = (v:unknown,field:string,min=0):number => {\n  if(typeof v!=='number'||!Number.isFinite(v)||v<min||Math.abs(v)>Number.MAX_SAFE_INTEGER)throw new Error(`Invalid ${field}.`);return v;\n};\nconst optionalText = (o:Record<string,unknown>,key:string):string|undefined => o[key]===undefined?undefined:text(o[key],key);\nconst strings = (v:unknown,field:string,allowEmpty=false):string[]=>{\n  if(!Array.isArray(v)||(!allowEmpty&&!v.length)||v.length>256)throw new Error(`Invalid ${field}.`);\n  const out=v.map(x=>text(x,field));if(new Set(out).size!==out.length)throw new Error(`Duplicate ${field}.`);return out;\n};\nconst boolean = (v:unknown,field:string):boolean=>{if(typeof v!=='boolean')throw new Error(`Invalid ${field}.`);return v;};\nconst optionalNumber=(o:Record<string,unknown>,key:string)=>o[key]===undefined?undefined:num(o[key],key);\nfunction onlyKeys(o:Record<string,unknown>,keys:string[],label:string):void{\n  for(const k of Object.keys(o))if(!keys.includes(k))throw new Error(`Unknown ${label} field: ${k}.`);\n}\n/** All unrecognized fields are rejected, never secretly retained in metadata-only evidence. */","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/core/evidence.ts#L46-L82","documentation":"object is the evidence-module validator requiring a field to be a plain object (not null, not an array). It throws 'Invalid <field>: object required.' when the value is missing, a primitive, an array, or null. Nested sections of observations, policies, and bundles all route through it.","triggerScenarios":"Calling validateObservation/validatePolicy or builders with a section set to null, an array, a string, or simply omitted; JSON payloads where an object was serialized as a list or flattened.","commonSituations":"A producer writing [] where an object map was expected; JSON null for absent optional sections; refactored payload shapes after a version upgrade; hand-built payloads that nested one level too shallow.","solutions":["Locate the named field and make it a non-null, non-array object: {} at minimum if empty is allowed.","Replace null with an empty object or remove the key only where the field is genuinely optional per the schema.","Fix producers that serialize maps as arrays (use keyed objects).","Diff your payload against the current evidence schema to catch nesting-depth changes."],"exampleFix":"// before\nvalidatePolicy({ authority: null })\n// after\nvalidatePolicy({ authority: { permitted: [], denied: [] } })","handlingStrategy":"type-guard","validationCode":"function checkObject(v, field) {\n  if (!v || typeof v !== 'object' || Array.isArray(v)) throw new Error(`${field} must be a plain object`);\n}","typeGuard":"const isPlainObject = (v) => !!v && typeof v === 'object' && !Array.isArray(v);","tryCatchPattern":"try {\n  validatePolicy(policy);\n} catch (e) {\n  if (e.message.includes('object required')) {\n    console.error(`${e.message} — section missing or wrong shape in payload`);\n  } else throw e;\n}","preventionTips":["Never serialize absent sections as null or []; omit the key or use {} per the schema.","Keep producers and consumers on the same schema version to avoid nesting-shape drift.","Add a pre-validate step that walks required sections and checks isPlainObject on each.","Beware JSON round-trips that turn empty maps into arrays or null."],"tags":["validation","evidence","schema","type-check"],"backgroundTag":"type-mismatch","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}