{"record":{"id":"a337556a4df986cb","repo":"Hmbown/CodeWhale","slug":"hunt-verdict-task-update-must-be-a-string","errorCode":null,"errorMessage":"hunt_verdict task update must be a string","messagePattern":"hunt_verdict task update must be a string","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/task_manager.rs","lineNumber":2126,"sourceCode":"                .context(\"Failed to parse gate task update\")?;\n            let summary = format!(\"Gate {} {}: {}\", gate.gate, gate.status, gate.summary);\n            task.gates.retain(|existing| existing.id != gate.id);\n            task.gates.push(gate.clone());\n            push_timeline_entry(\n                task,\n                TaskTimelineEntry {\n                    timestamp: now,\n                    kind: \"gate\".to_string(),\n                    summary: summarize_text(&summary, TIMELINE_SUMMARY_LIMIT),\n                    detail_path: gate.log_path,\n                },\n            );\n        }\n\n        if let Some(value) = updates.get(\"hunt_verdict\") {\n            let raw = value\n                .as_str()\n                .ok_or_else(|| anyhow!(\"hunt_verdict task update must be a string\"))?;\n            let verdict = normalize_hunt_verdict(raw)?;\n            if task.hunt_verdict.as_deref() != Some(verdict) {\n                task.hunt_verdict = Some(verdict.to_string());\n                push_timeline_entry(\n                    task,\n                    TaskTimelineEntry {\n                        timestamp: now,\n                        kind: \"hunt_verdict\".to_string(),\n                        summary: format!(\"Hunt verdict updated: {verdict}\"),\n                        detail_path: None,\n                    },\n                );\n            }\n        }\n\n        if let Some(value) = updates.get(\"attempt\") {\n            let attempt: TaskAttemptRecord = serde_json::from_value(value.clone())\n                .context(\"Failed to parse attempt task update\")?;","sourceCodeStart":2108,"sourceCodeEnd":2144,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/task_manager.rs#L2108-L2144","documentation":"While applying task updates, if the updates object contains a 'hunt_verdict' key, its value must be a JSON string (value.as_str()). Any other JSON type — boolean, number, null, array, object — is rejected before normalize_hunt_verdict runs. The verdict string itself is then normalized; invalid strings fail in normalize_hunt_verdict with a separate error.","triggerScenarios":"Applying task updates like {\"hunt_verdict\": true}, {\"hunt_verdict\": 1}, or {\"hunt_verdict\": {\"verdict\": \"clean\"}} — the value is present but not a string.","commonSituations":"A model or integration emits a boolean verdict (true/false) or a nested object instead of the expected string literal such as 'clean' or 'suspicious'.","solutions":["Pass the verdict as a JSON string: {\"hunt_verdict\": \"clean\"} (use whatever verdict spelling normalize_hunt_verdict accepts).","Omit the key entirely if no verdict update is needed.","Validate the updates payload shape before calling the update API."],"exampleFix":"// before\nupdates = { \"hunt_verdict\": true }\nupdates = { \"hunt_verdict\": { \"result\": \"clean\" } }\n\n// after\nupdates = { \"hunt_verdict\": \"clean\" }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isValidHuntVerdictUpdate(updates: Record<string, unknown>): boolean {\n  const v = updates['hunt_verdict'];\n  return v === undefined || typeof v === 'string';\n}","tryCatchPattern":"if (updates.hunt_verdict !== undefined && typeof updates.hunt_verdict !== 'string') {\n  updates.hunt_verdict = String(updates.hunt_verdict);\n}\ntry { await applyTaskUpdates(id, updates); }\ncatch (e) {\n  if (e.message.includes('hunt_verdict task update must be a string')) { /* fix payload to string, retry once */ }\n  else throw e;\n}","preventionTips":["Define hunt_verdict in the schema as a plain string enum; reject objects/booleans at the boundary.","When copying verdicts from structured output, unwrap to the string field before applying updates."],"tags":["tasks","task-manager","json","type-validation","hunt-verdict"],"backgroundTag":"json-type-mismatch","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}