ZhuLinsen/daily_stock_analysis · error · LocalCliExtractionError
schema_validation_failed
schema_validation_failed
Error message
schema_validation_failed
What it means
A structured LocalCliExtractionError with code schema_validation_failed, raised while parsing the newline-delimited JSON event stream from the local CLI (opencode) backend. Every decoded event must be a JSON object; a non-object (string, number, list element, null) at a given event_index fails validation. It indicates the child process emitted a payload that does not conform to the expected event protocol.
Source
Thrown at src/llm/local_cli_backend.py:1980
GenerationErrorCode.INVALID_JSON,
"invalid_json",
details={"error": "json_decoder_made_no_progress"},
)
index = next_index
if isinstance(decoded, list):
for item in decoded:
event_index += 1
yield _validate_opencode_event(item, event_index=event_index)
continue
event_index += 1
yield _validate_opencode_event(decoded, event_index=event_index)
def _validate_opencode_event(value: Any, *, event_index: int) -> Dict[str, Any]:
if not isinstance(value, dict):
raise LocalCliExtractionError(
GenerationErrorCode.SCHEMA_VALIDATION_FAILED,
"schema_validation_failed",
details={"event_index": event_index, "expected": "object_event"},
)
event_type = value.get("type")
if not isinstance(event_type, str) or not event_type.strip():
raise LocalCliExtractionError(
GenerationErrorCode.SCHEMA_VALIDATION_FAILED,
"schema_validation_failed",
details={"event_index": event_index, "expected": "event_type"},
)
return value
def _opencode_blocked_event_reason(event: Dict[str, Any], event_type_lower: str) -> str:
if (
event_type_lower in _OPENCODE_BLOCKED_EVENT_TYPES
or any(blocked in event_type_lower for blocked in _OPENCODE_BLOCKED_EVENT_TYPES)View on GitHub (pinned to 5159bd72e8)
Solutions
- Reproduce the raw subprocess output (run the same CLI command manually) and inspect which line is a non-object JSON value
- Pin or upgrade the local CLI to the version whose event protocol this backend expects
- Ensure nothing else writes to the captured stdout of the subprocess (redirect debug logs to stderr)
- If you wrap the CLI in a script, make the wrapper only emit newline-delimited JSON objects with a string 'type' field
Defensive patterns
Strategy: try-catch
Validate before calling
import json
def is_object_event(line: str) -> bool:
try:
value = json.loads(line)
except json.JSONDecodeError:
return False
return isinstance(value, dict) Type guard
from typing import Any, Dict
def is_opencode_event(value: Any) -> "typeguard":
return isinstance(value, dict) and isinstance(value.get("type"), str) and bool(value.get("type").strip()) Try / catch
try:
for event in stream_opencode_events(proc):
handle(event)
except LocalCliExtractionError as exc:
if exc.error_code == GenerationErrorCode.SCHEMA_VALIDATION_FAILED:
log.error("CLI event protocol violation: %s", exc.details)
capture_raw_stream_for_diagnosis()
raise Prevention
- Pin the local CLI version so its event protocol cannot drift
- Route all subprocess debug output to stderr, never the captured event stream
- Keep raw stream dumps behind a debug flag so protocol violations are diagnosable
When it happens
Trigger: The CLI subprocess prints a bare JSON scalar or string line (e.g. "\"done\"" or "42") into stdout that is captured as an event; a list payload containing non-object items; any third-party tool, progress bar, or stray log line interleaved into the event stream that decodes to a non-object JSON value.
Common situations: The local CLI version changed its output protocol; another tool writes to the same stdout; debug logging accidentally routed to stdout; a wrapper script echoing JSON fragments; malformed partial lines after a truncated buffer flush.
Related errors
- unsafe_config
- 不支持的 portfolio: {portfolio}
- Event alert rules must be a JSON array
- Event alert rules list must contain only objects; invalid en
- Event alert rule must be an object
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/5ffd30c1ed43d5c0.
Report an issue: GitHub.