{"record":{"id":"a1c8d443e6c1730d","repo":"xpipe-io/xpipe","slug":"couldn-t-parse-response","errorCode":null,"errorMessage":"Couldn't parse response","messagePattern":"Couldn't parse response","errorType":"exception","errorClass":"BeaconConnectorException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/xpipe/app/beacon/BeaconClient.java","lineNumber":92,"sourceCode":"            se.get().throwError();\n        }\n\n        var ce = parseClientError(response);\n        if (ce.isPresent()) {\n            throw ce.get().throwException();\n        }\n\n        try {\n            var reader = JacksonMapper.getDefault().readerFor(prov.getResponseClass());\n            var emptyResponseClass = prov.getResponseClass().getDeclaredFields().length == 0;\n            var body = response.body();\n            if (emptyResponseClass && body.isBlank()) {\n                return createDefaultResponse(prov);\n            }\n            var v = (RES) reader.readValue(body);\n            return v;\n        } catch (Exception ex) {\n            throw new BeaconConnectorException(\"Couldn't parse response\", ex);\n        }\n    }\n\n    @SneakyThrows\n    @SuppressWarnings(\"unchecked\")\n    private <REQ> REQ createDefaultResponse(BeaconInterface<?> beaconInterface) {\n        var c = beaconInterface.getResponseClass().getDeclaredMethod(\"builder\");\n        c.setAccessible(true);\n        var b = c.invoke(null);\n        var m = b.getClass().getDeclaredMethod(\"build\");\n        m.setAccessible(true);\n        return (REQ) beaconInterface.getResponseClass().cast(m.invoke(b));\n    }\n\n    public <REQ, RES> RES performRequest(REQ req)\n            throws BeaconConnectorException, BeaconClientException, BeaconServerException {\n        ObjectNode node = JacksonMapper.getDefault().valueToTree(req);\n        var prov = BeaconInterface.byRequest(req);","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/xpipe-io/xpipe/blob/d85ca821baa46092a320ebb13546d7240adb74f8/app/src/main/java/io/xpipe/app/beacon/BeaconClient.java#L74-L110","documentation":"After receiving a response, performRequest deserializes the JSON body into the expected response type (RES) with Jackson. If readValue fails — because the body is HTML/error text, an unexpected schema, or an empty/garbled payload — the raw exception is wrapped as BeaconConnectorException('Couldn't parse response').","triggerScenarios":"The daemon returned non-JSON content (e.g. a proxy error page, plain-text stack trace); the response JSON does not match the expected response class fields; a version mismatch between client and daemon produces different schemas; the body is blank when a non-empty response class was expected.","commonSituations":"Client and xpipe daemon at different versions; an intermediary (reverse proxy, captive portal) intercepting the request; hitting the wrong endpoint/port so an HTML error page is returned; daemon bug returning malformed JSON.","solutions":["Log/inspect the raw response body (enable AppProperties printBeaconMessages or print response.body()) to see what was actually returned.","Align client and daemon versions so the response schema matches the compiled response classes.","Confirm the request targets the correct beacon endpoint URL (no proxy interference, correct path/port).","Catch BeaconConnectorException, inspect the cause (JsonProcessingException) and fall back to re-issuing the request or failing gracefully."],"exampleFix":"// before\nvar res = client.performRequest(req); // may throw parse error\n// after\ntry {\n    var res = client.performRequest(req);\n} catch (BeaconConnectorException e) {\n    LOG.error(\"Beacon returned unparseable body; check daemon/client version match\", e);\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":"// inspect body before parsing assumptions\nString body = lastResponseBody; // via printBeaconMessages or response capture\nboolean looksJson = body != null && body.strip().startsWith(\"{\");","typeGuard":"boolean isJsonObject(String s) {\n    return s != null && s.strip().startsWith(\"{\") && s.strip().endsWith(\"}\");\n}","tryCatchPattern":"try {\n    return client.performRequest(req);\n} catch (BeaconConnectorException e) {\n    if (e.getCause() instanceof JsonProcessingException) {\n        LOG.error(\"Non-JSON or schema-mismatched beacon response; check client/daemon versions\", e);\n    }\n    throw e;\n}","preventionTips":["Keep client and daemon versions aligned","Avoid proxies that rewrite HTTP error pages into the response body","Enable printBeaconMessages while developing to inspect raw bodies"],"tags":["http","json","deserialization","beacon"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"d85ca821baa46092a320ebb13546d7240adb74f8","analyzedAt":"2026-09-06T14:30:08.251Z","contentChangedAt":"2026-09-06T14:30:08.251Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}