{"record":{"id":"f42c01b5e7a12814","repo":"karatelabs/karate","slug":"token-endpoint-returned-unexpected-response-truncate","errorCode":null,"errorMessage":"Token endpoint returned unexpected response: \" + truncate(bodyString)","messagePattern":"Token endpoint returned unexpected response: \" \\+ truncate\\(bodyString\\)","errorType":"exception","errorClass":"OAuth2Exception","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/http/AuthorizationCodeAuthHandler.java","lineNumber":203,"sourceCode":"\n        // Optional client_secret (for confidential clients)\n        if (config.containsKey(\"client_secret\")) {\n            builder.formField(\"client_secret\", config.get(\"client_secret\"));\n        }\n\n        builder.header(\"Accept\", \"application/json\");\n\n        try {\n            HttpResponse response = builder.invoke(\"post\");\n            String bodyString = response.getBodyString();\n            Json json;\n            try {\n                json = Json.of(bodyString);\n            } catch (Exception e) {\n                throw new OAuth2Exception(\"Token endpoint returned invalid response: \" + truncate(bodyString));\n            }\n            if (!json.isObject()) {\n                throw new OAuth2Exception(\"Token endpoint returned unexpected response: \" + truncate(bodyString));\n            }\n            Map<String, Object> data = json.asMap();\n            if (data.containsKey(\"error\")) {\n                String error = String.valueOf(data.get(\"error\"));\n                String desc = data.containsKey(\"error_description\") ? String.valueOf(data.get(\"error_description\")) : null;\n                throw new OAuth2Exception(\"Token request failed: \" + error + (desc != null ? \" - \" + desc : \"\"));\n            }\n\n            logger.debug(\"Token exchange successful\");\n            return OAuth2Token.fromMap(data);\n\n        } catch (OAuth2Exception e) {\n            logger.error(\"Token exchange failed: {}\", e.getMessage());\n            throw new OAuth2Exception(\"Token exchange failed: \" + e.getMessage(), e);\n        } catch (Exception e) {\n            logger.error(\"Token exchange failed: {}\", e.getMessage());\n            throw new OAuth2Exception(\"Token exchange failed: \" + e.getMessage(), e);\n        }","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/http/AuthorizationCodeAuthHandler.java#L185-L221","documentation":"Thrown by exchangeCodeForToken when the token endpoint returns valid JSON but the top-level value is not a JSON object. RFC 6749 requires the token response to be a JSON object; arrays, strings, or numbers are rejected so the library cannot extract access_token and related fields.","triggerScenarios":"Token endpoint responded with parseable JSON whose root is an array, string, number, or boolean instead of an object (json.isObject() is false).","commonSituations":"Misconfigured provider or mock/stub returning a JSON array; a custom or poorly-implemented OAuth server returning a bare JSON string; hitting an API that echoes requests as JSON arrays.","solutions":["Confirm the provider's token endpoint returns a JSON object like {\"access_token\":\"...\",\"token_type\":\"...\"}.","If testing against a mock, fix the mock to return a top-level JSON object.","Check you are not accidentally calling a different endpoint (e.g. a JWKS or userinfo URL) that returns different JSON shapes."],"exampleFix":"// mock token endpoint before\nreturn Json.array().append(\"token-value\").toString();\n// after\nreturn Json.object().set(\"access_token\", \"token-value\").set(\"token_type\", \"bearer\").toString();","handlingStrategy":"validation","validationCode":"// If you control a mock/stub token endpoint, assert the shape before serving\nString body = mockTokenResponse();\nJson json = Json.of(body);\nif (!json.isObject()) {\n    throw new IllegalStateException(\"Token mock must return a JSON object\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    handler.token();\n} catch (OAuth2Exception e) {\n    if (e.getMessage().contains(\"unexpected response\")) {\n        logger.error(\"Token endpoint returned non-object JSON: {}\", e.getMessage());\n    }\n}","preventionTips":["Verify provider docs: token responses are always JSON objects.","Keep mocks/stubs aligned with RFC 6749 response shape.","Do not reuse JWKS/userinfo URLs as the token endpoint."],"tags":["oauth2","json","http"],"backgroundTag":"unexpected-response-shape","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}