Skip to content

bug: diagnose InvalidInput parse error on /api/dashboard (root cause unconfirmed) #271

Description

@Strycher

Symptom (confirmed)

dcc-panel7 logs ERROR DATA: parse error — InvalidInput on every /api/dashboard poll. Red sync indicator persists. WiFi green.

Confirmed evidence (do not extrapolate beyond this)

What Value Source
Bridge /api/dashboard response size for dcc-panel7 144,427 bytes curl -o /tmp/d.json -w '%{size_download}' from Pi shell
HTTP status from bridge 200 OK Bridge access logs
Device-side parse outcome InvalidInput Device serial (ERROR DATA: parse error — InvalidInput)
All bridge adapters status ok, ~0 errors GET /api/adapters

Hypotheses — UNCONFIRMED, must test

ArduinoJson v7 InvalidInput means "the bytes I tried to parse are not valid JSON." That outcome is consistent with several distinct causes:

  1. Body truncated mid-stream (e.g., HTTP collector realloc returned NULL at one doubling step; the partial buffer was still passed to deserializeJson)
  2. Body received in full but contains an embedded NUL byte (NUL terminates the C string for deserializeJson even if the underlying buffer has more data)
  3. Body received in full and JSON-valid but ArduinoJson _doc capacity exhausted during parse (different from InvalidInput in v6, but possible in v7 depending on configuration)
  4. Body bytes corrupted in flight (TLS/HTTP framing issue, less likely on plaintext HTTP over LAN)
  5. Body received correctly but at a point where prior parses left state in _doc (_doc.clear() is called before parse — should rule this out, but worth verifying)

Each of these has a different fix. Picking one without evidence wastes effort and likely produces a non-fix.

Diagnostic plan

Add temporary logging to firmware/src/platform/p4/network_p4.cpp (httpEventCb + httpGet) and firmware/src/data_service.cpp (parse path):

Datapoint Tells us
resp.bodyLen after httpGet returns Did the device actually receive 144 KB, or less? Distinguishes truncation from non-truncation root causes.
Last 80 bytes of resp.body Does the buffer end with } (well-formed close) or mid-string (truncation)?
Each realloc invocation: old cap → new cap, return value Where in the cascade did realloc happen? Did any step return NULL?
Free heap before fetch + after fetch Heap pressure context for the realloc story.
Free PSRAM before fetch Confirms PSRAM is available if we later choose to move the buffer there.

These are diagnostic-only changes — no behavioral fix. Once we know the actual failure point, we open a separate fix issue with evidence in hand.

Why this matters

Previous attempt (closed #270 / Citadel-d12) jumped to "use PSRAM" based on the heap-fragmentation hypothesis without testing it. That's exactly the SAFELANE §5 prohibited behavior: claiming a test "proved" a cause when it only proved a symptom. The fix may end up being PSRAM, but it may also be: increase initial collector capacity, fix a NUL-byte in the bridge response, increase ArduinoJson doc capacity, or something not yet on the list. The diagnostic step is cheap; the wrong fix is expensive.

Acceptance for this issue

This issue closes when we have answered: what specifically is the parser seeing when it returns InvalidInput, and what was the last successful step before the failure. That answer goes into a follow-up bug + fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions