{"record":{"id":"ea43e05ed9add48c","repo":"karatelabs/karate","slug":"token-refresh-failed","errorCode":null,"errorMessage":"Token refresh failed: ","messagePattern":"Token refresh failed: ","errorType":"exception","errorClass":"OAuth2Exception","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/http/OAuth2TokenManager.java","lineNumber":109,"sourceCode":"                String errorMessage = \"Token refresh failed: expected JSON object but received \" +\n                    (json.isArray() ? \"array\" : \"primitive value\");\n                logger.error(errorMessage);\n                currentToken = null;\n                throw new OAuth2Exception(errorMessage);\n            }\n\n            Map<String, Object> data = json.asMap();\n            OAuth2Token newToken = OAuth2Token.fromMap(data);\n            storeToken(newToken);\n            logger.debug(\"Token refreshed successfully\");\n            return newToken;\n        } catch (OAuth2Exception e) {\n            throw e;\n        } catch (Exception e) {\n            String errorMessage = \"Token refresh failed: \" + e.getMessage();\n            logger.error(errorMessage);\n            currentToken = null;\n            throw new OAuth2Exception(errorMessage, e);\n        }\n    }\n\n    /**\n     * Clear stored token\n     */\n    public void clearToken() {\n        currentToken = null;\n        logger.debug(\"Token cleared\");\n    }\n\n    /**\n     * Parse OAuth error response and return a user-friendly message\n     */\n    private String parseOAuthError(String body, int status) {\n        if (body == null || body.isBlank()) {\n            return \"Token refresh failed: server returned HTTP \" + status + \" with empty response\";\n        }","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/http/OAuth2TokenManager.java#L91-L127","documentation":"refreshToken() wraps any unexpected exception during the refresh round-trip into OAuth2Exception with the original message appended, after clearing the cached token. This is the catch-all so callers always see an OAuth2Exception with context about the token refresh that failed.","triggerScenarios":"Any exception during token refresh other than the handled parse/shape errors: connection failures, timeouts, HTTP 4xx/5xx when the client throws, IO errors reading the body.","commonSituations":"IdP unreachable (DNS/firewall), client credentials rejected with 401 from the token endpoint, TLS handshake failure, network blips during long test runs.","solutions":["Read the wrapped cause/exception message for the root problem (the text after 'Token refresh failed: ').","Verify network reachability and TLS trust to the identity provider.","Check client_id/client_secret correctness — 401/400 at the token endpoint surfaces here.","After fixing, re-invoke the token flow; the manager clears the bad token so the next call refreshes cleanly.","­"],"exampleFix":"// before\n// message only: 'Token refresh failed: null'\n// after\nnew OAuth2Exception(errorMessage, e); // inspect e / cause for real reason, e.g. UnknownHostException","handlingStrategy":"try-catch","validationCode":"// preflight: network + credentials\nif (!isReachable(tokenHost)) throw new Error('token endpoint unreachable'); if (!clientId || !clientSecret) throw new Error('missing client credentials');","typeGuard":null,"tryCatchPattern":"try { token = mgr.refresh(); } catch (OAuth2Exception e) { Throwable cause = e.getCause(); log.error('Refresh failed: ' + e.getMessage(), cause); if (cause instanceof java.io.IOException) retryWithBackoff(); else reauthenticate(); }","preventionTips":["Inspect the wrapped cause for the true root cause (DNS, TLS, HTTP status)","Verify client_id/client_secret and grant configuration","Add retry with backoff for transient network errors","Monitor the token endpoint availability in CI environments"],"tags":["oauth2","token-refresh","wrapped-exception"],"backgroundTag":"oauth-token-exchange-failed","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"}