Yeachan-Heo/oh-my-codex · error · Error

visual_verdict.${field} must contain strings

Error message

visual_verdict.${field} must contain strings

What it means

Inside a visual_verdict string-array field, one of the array elements is not a string (number, object, null, boolean). asTrimmedStringArray throws because every element of observations/next_actions must be a string (empty strings are trimmed and filtered, but non-strings are rejected).

Source

Thrown at src/visual/verdict.ts:29

  differences: string[];
  suggestions: string[];
  reasoning: string;
}

export interface VisualLoopFeedback extends VisualVerdict {
  threshold: number;
  passes_threshold: boolean;
  next_actions: string[];
}

function asTrimmedStringArray(value: unknown, field: string): string[] {
  if (!Array.isArray(value)) {
    throw new Error(`visual_verdict.${field} must be an array`);
  }
  return value
    .map((item) => {
      if (typeof item !== 'string') {
        throw new Error(`visual_verdict.${field} must contain strings`);
      }
      return item.trim();
    })
    .filter((item) => item.length > 0);
}

function parseVisualVerdictStatus(value: unknown): VisualVerdictStatus {
  if (typeof value !== 'string') {
    throw new Error(`visual_verdict.verdict must be one of: ${VISUAL_VERDICT_STATUSES.join('|')}`);
  }
  const normalized = value.trim().toLowerCase();
  if (!VISUAL_VERDICT_STATUSES.includes(normalized as VisualVerdictStatus)) {
    throw new Error(`visual_verdict.verdict must be one of: ${VISUAL_VERDICT_STATUSES.join('|')}`);
  }
  return normalized as VisualVerdictStatus;
}

export function parseVisualVerdict(input: unknown): VisualVerdict {

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Coerce or drop non-string elements on the producer side before serializing
  2. Map numeric/null entries to strings (String(item)) or omit them
  3. Validate model output with a schema before feeding it to parseVisualVerdict

Example fix

// before
{ "observations": ["ok", 42] }
// after
{ "observations": ["ok", "42"] }
Defensive patterns

Strategy: type-guard

Validate before calling

if (!arr.every(x => typeof x === 'string')) arr = arr.map(String);

Type guard

const isStringArray = (v: unknown): v is string[] => Array.isArray(v) && v.every(x => typeof x === 'string');

Prevention

When it happens

Trigger: Calling parseVisualVerdict where e.g. visual_verdict.next_actions is ["fix css", 3] or [null].

Common situations: LLM output mixing types into arrays (numbers as step indices); JSON produced from untyped languages; verdict fixtures with nulls for empty items.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/ada248b73bc83b8c. Report an issue: GitHub.