Hmbown/CodeWhale · error · Error
Invalid .
Error message
Invalid ${field}. What it means
enumValue is the evidence-module validator for string fields restricted to a fixed set of allowed values. It throws when a value is not a string or is not one of the allowed literals, with the field name interpolated into the message (e.g. 'Invalid kind.'). It guarantees enum-typed fields in observations, policies, and bundles are exactly one of the documented values.
Solutions
- Check the error's field name and compare the value against the allowed literals for that field in the evidence schema.
- Fix casing/spelling to match the documented enum member exactly (comparison is case-sensitive).
- Ensure the field is present — undefined fails the string check too.
- If your producer predates a schema rename, regenerate or migrate the evidence payload to the current schema.
Example fix
// before
validateObservation({ kind: 'syscall' }) // not an allowed value
// after
validateObservation({ kind: 'sandbox_escape' }) // one of the schema's enum members Defensive patterns
Strategy: validation
Validate before calling
const KINDS = ['sandbox_escape','syscall','net_connect','file_write']; // substitute the schema's literals
function checkEnum(v, field, values) {
if (typeof v !== 'string' || !values.includes(v)) throw new Error(`${field} must be one of: ${values.join(', ')}`);
} Type guard
const isOneOf = (v, values) => typeof v === 'string' && values.includes(v);
Try / catch
try {
validateObservation(observation);
} catch (e) {
if (e.message.startsWith('Invalid ') && !e.message.includes(':')) {
console.error(`enum field rejected: ${e.message}; check spelling/casing against the schema`);
} else throw e;
} Prevention
- Copy enum literals from the schema/types rather than typing them from memory.
- Use a const object or union type for enum values so typos become compile errors.
- Validate enum fields at the producer boundary before serializing evidence.
- When upgrading the library, diff enum members for renames and migrate payloads.
When it happens
Trigger: Calling validateObservation, validatePolicy, or the sources/g builders with a payload whose enum field (e.g. kind, effect class) is misspelled, has wrong casing, is a number/boolean, or is absent (undefined).
Common situations: Hand-writing evidence JSON with a typo like "permitted" vs "allowed"; a schema change between library versions renaming an enum member; serializing from another language where the enum became a number; forgetting to set the field at all.
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
- Invalid : object required.
- agent profile reasoning_effort must be one of: inherit…
- Choose approve or decline
- clipboard action must be "read" or "write
- Codewhale terminal receipt contained a non-scalar field
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/a3f03361bd06a793.
Report an issue: GitHub.
Appendix: source
Thrown at pet/src/core/evidence.ts:61
count: number; lastReceivedAt: number | null; sequenceGaps: number;
}
export interface BoundaryFinding {
id: string; code: string; severity: 'info'|'warning'|'critical';
title: string; detail: string; recordIds: string[]; time: number;
}
export interface Interaction {
runId: string; sandboxId?: string; group?: string; target: string;
kind: string; stage: Stage; effect: Effect; count: number; recordIds: string[];
}
export interface BoundaryAnalysis {
version: 1; omittedFindings: number; asOf: number; inputRecords: number; visibleRecords: number; uniqueRecords: number;
futureRecords: number; findings: BoundaryFinding[]; coverage: CoverageRow[];
interactions: Interaction[]; runs: number; sandboxes: number; externalEffects: number;
unknownEffects: number; authority: { permitted: number; denied: number; unknown: number };
provenance: string;
}
const enumValue = <T extends string>(v:unknown, values: readonly T[], field:string): T => {
if(typeof v!=='string'||!values.includes(v as T))throw new Error(`Invalid ${field}.`);return v as T;
};
const object = (v:unknown, field:string): Record<string,unknown> => {
if(!v||typeof v!=='object'||Array.isArray(v))throw new Error(`Invalid ${field}: object required.`);return v as Record<string,unknown>;
};
const text = (v:unknown, field:string, max=256):string => {
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;
};
const num = (v:unknown,field:string,min=0):number => {
if(typeof v!=='number'||!Number.isFinite(v)||v<min||Math.abs(v)>Number.MAX_SAFE_INTEGER)throw new Error(`Invalid ${field}.`);return v;
};
const optionalText = (o:Record<string,unknown>,key:string):string|undefined => o[key]===undefined?undefined:text(o[key],key);
const strings = (v:unknown,field:string,allowEmpty=false):string[]=>{
if(!Array.isArray(v)||(!allowEmpty&&!v.length)||v.length>256)throw new Error(`Invalid ${field}.`);
const out=v.map(x=>text(x,field));if(new Set(out).size!==out.length)throw new Error(`Duplicate ${field}.`);return out;
};
const boolean = (v:unknown,field:string):boolean=>{if(typeof v!=='boolean')throw new Error(`Invalid ${field}.`);return v;};
const optionalNumber=(o:Record<string,unknown>,key:string)=>o[key]===undefined?undefined:num(o[key],key);
function onlyKeys(o:Record<string,unknown>,keys:string[],label:string):void{View on GitHub (pinned to 433685b202)