HKUDS/Vibe-Trading · error · ValueError

audit rows require criterion_id and result

Error message

audit rows require criterion_id and result

What it means

Each audit row dict must carry non-empty criterion_id and result after stripping. This ensures the audit trail is actually attributable to a criterion. Missing keys, empty strings, or whitespace-only values all trigger it.

Source

Thrown at agent/src/tools/goal_tool.py:51


def _coerce_audit_rows(value: Any) -> list[AuditRow]:
    """Coerce model/API-style audit rows into dataclasses."""
    if value in (None, ""):
        return []
    if isinstance(value, str):
        value = json.loads(value)
    if not isinstance(value, list):
        raise ValueError("audit must be a list")

    rows: list[AuditRow] = []
    for item in value:
        if not isinstance(item, dict):
            raise ValueError("audit rows must be objects")
        criterion_id = str(item.get("criterion_id") or "").strip()
        result = str(item.get("result") or "").strip()
        if not criterion_id or not result:
            raise ValueError("audit rows require criterion_id and result")
        rows.append(
            AuditRow(
                criterion_id=criterion_id,
                result=result,
                evidence_ids=_coerce_string_list(item.get("evidence_ids")),
                notes=str(item.get("notes") or ""),
            )
        )
    return rows


def _sha256_file(path: Path) -> str:
    """Return the sha256 digest for a local artifact."""
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for chunk in iter(lambda: handle.read(1024 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Populate criterion_id and result on every row
  2. Skip empty rows before submission: rows=[r for r in rows if r.get('criterion_id') and r.get('result')]
  3. Add client-side required-field validation for the audit form

Example fix

# before
{"criterion_id": "c1"}
# after
{"criterion_id": "c1", "result": "pass"}
Defensive patterns

Strategy: validation

Validate before calling

audit = [r for r in audit if str(r.get("criterion_id", "")).strip() and str(r.get("result", "")).strip()]

Type guard

def row_is_complete(r: dict) -> bool:
    return bool(str(r.get("criterion_id") or "").strip() and str(r.get("result") or "").strip())

Try / catch

try:
    execute(audit=audit)
except ValueError as e:
    if "require criterion_id and result" in str(e):
        audit = [r for r in audit if row_is_complete(r)]
        execute(audit=audit)
    raise

Prevention

When it happens

Trigger: audit=[{"criterion_id": "", "result": "pass"}] or a row with only notes/evidence but no ids.

Common situations: LLM omitting fields it considers obvious; partial dicts merged from templates; frontend forms not enforcing required inputs.

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 HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/ea96b72ab33c216c. Report an issue: GitHub.