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:
- Body truncated mid-stream (e.g., HTTP collector
realloc returned NULL at one doubling step; the partial buffer was still passed to deserializeJson)
- 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)
- 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)
- Body bytes corrupted in flight (TLS/HTTP framing issue, less likely on plaintext HTTP over LAN)
- 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.
Symptom (confirmed)
dcc-panel7 logs
ERROR DATA: parse error — InvalidInputon every/api/dashboardpoll. Red sync indicator persists. WiFi green.Confirmed evidence (do not extrapolate beyond this)
/api/dashboardresponse size for dcc-panel7curl -o /tmp/d.json -w '%{size_download}'from Pi shellInvalidInputERROR DATA: parse error — InvalidInput)ok, ~0 errorsGET /api/adaptersHypotheses — UNCONFIRMED, must test
ArduinoJson v7
InvalidInputmeans "the bytes I tried to parse are not valid JSON." That outcome is consistent with several distinct causes:reallocreturned NULL at one doubling step; the partial buffer was still passed todeserializeJson)deserializeJsoneven if the underlying buffer has more data)_doccapacity exhausted during parse (different from InvalidInput in v6, but possible in v7 depending on configuration)_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) andfirmware/src/data_service.cpp(parse path):resp.bodyLenafterhttpGetreturnsresp.body}(well-formed close) or mid-string (truncation)?reallocinvocation: old cap → new cap, return valueThese 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.