Skip to content

fix(scan): non-fatal batch errors + non-JSON response diagnostics (#316)#317

Merged
ajianaz merged 1 commit into
developfrom
fix/316-scan-json-parse
Jun 17, 2026
Merged

fix(scan): non-fatal batch errors + non-JSON response diagnostics (#316)#317
ajianaz merged 1 commit into
developfrom
fix/316-scan-json-parse

Conversation

@ajianaz

@ajianaz ajianaz commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #316cora scan aborts with failed to parse LLM JSON response: expected value at line 1 column 1 on large batches.

Root cause

When a scan batch is large, the LLM/provider returns a response that isn't valid JSON (truncated, wrapped in prose, or an error/rate-limit body). parse_scan_response then hard-failed the entire scan with a minimal error, no per-file results, and no way to see what the provider actually returned.

Changes

1. Early non-JSON guard (parse_scan_response)

Add looks_like_json_array() that checks whether the trimmed response (after optional ```json fences) starts with [ or `{`. If not, fail fast with `non_json_error_message()` which includes:

  • response length,
  • raw response prefix (first 512 bytes, whitespace-collapsed via preview_raw()).

So users can immediately tell whether it's a provider error page, rate-limit message, or prose wrapper.

2. Per-batch parse failures are now non-fatal by default

In execute_scan, each batch call is wrapped in match. On Err:

  • log at warn level with batch index + file list (shows even without --verbose),
  • print a yellow stderr warning,
  • push to skipped_batches and continue with the next batch,
  • print a summary of skipped batch count after the loop.

--no-continue-on-batch-error restores the old abort-on-failure behavior.

3. New --batch-files <N> flag (default: 20)

Lets users lower the max files per batch to work around provider token limits / rate-limits on large scans.

4. Better diagnostics

Both the truncated-JSON repair path and the general parse-error path now append the raw response prefix.

Tests

  • 14 new unit tests in src/engine/llm.rs covering looks_like_json_array, preview_raw, and parse_scan_response non-JSON rejection (HTML page, empty body, prose).
  • All existing 63 engine::llm tests still pass.
  • cargo clippy -- -D warnings clean, cargo fmt applied.

Versioning

Patch bump 0.6.00.6.1 per the existing release flow (GitFlow: merge to main via PR, then tag v0.6.1). No API breaking changes.

Checklist

  • cargo test passes
  • cargo clippy -- -D warnings clean
  • cargo fmt applied
  • CHANGELOG updated under ## [0.6.1]
  • Version bumped in Cargo.toml + Cargo.lock
  • CHANGELOG compare links fixed (added missing [0.6.0] entry)

- Add early non-JSON response guard in parse_scan_response: detect HTML
  error pages, rate-limit bodies, empty responses, and prose wrappers before
  attempting strict parse. Surface raw response prefix (first 512 bytes,
  whitespace-collapsed) in the error so users can diagnose truncation vs
  provider error vs prose.
- Make per-batch parse failures non-fatal by default: skip the failing batch
  with a stderr warning and warn-level log (with file list), continue with
  remaining batches. --no-continue-on-batch-error restores old abort behavior.
- Add --batch-files <N> flag (default 20) to cap files per LLM batch — lower
  it to work around provider token limits on large scans.
- Truncated-JSON repair path now also includes raw response prefix.
- Add 14 unit tests covering looks_like_json_array, preview_raw, and
  parse_scan_response non-JSON rejection.
- Bump version 0.6.0 → 0.6.1 (patch: bug fix, no API breaking changes).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: cora scan aborts with "failed to parse LLM JSON response" on large batches

1 participant