karatelabs/karate · error · OAuth2Exception

Could not start callback server on any configured port…

Error message

Could not start callback server on any configured port: [ports]. Please ensure at least one port is available, or configure different ports using 'callbackPort' or 'callbackPorts'. These ports must be registered as redirect URIs with your OAuth provider.

What it means

OAuth2Exception thrown by AuthorizationCodeAuthHandler.startCallbackServer when none of the configured callback ports (callbackPort / callbackPorts) can be bound. Karate runs a temporary local HTTP server to receive the OAuth redirect; without a bound port the authorization-code flow cannot complete. The cause (typically BindException / address already in use) is attached as lastException.

Solutions

  1. Free the conflicting process or choose free ports via callbackPorts (a list, so parallel runs can use distinct ports).
  2. Check what holds the port: `lsof -i :<port>` (Unix) or `netstat -ano` (Windows), then stop it.
  3. Register the chosen ports as redirect URIs (e.g. http://localhost:<port>/...) with your OAuth provider — an unregistered port fails later even if bound.
  4. Avoid privileged ports (<1024) unless running with the required privileges.

Example fix

// before
karate.configure('oauth', { callbackPort: 8080, /* ... */ });
// after: give several fallback ports and ensure they're registered as redirect URIs
karate.configure('oauth', { callbackPorts: [9001, 9002, 9003], /* ... */ });
Defensive patterns

Strategy: validation

Validate before calling

// before starting the OAuth flow, check the callback ports are bindable
int[] ports = {9001, 9002};
for (int p : ports) {
    try (var ss = new java.net.ServerSocket(p)) { /* ok */ }
    catch (IOException e) { throw new IllegalStateException("callback port in use: " + p); }
}

Try / catch

try {
    auth.start(); // triggers redirectUri -> startCallbackServer
} catch (OAuth2Exception e) {
    // all callback ports failed to bind
    throw new IllegalStateException("no free callback port among configured ports", e.getCause());
}

Prevention

When it happens

Trigger: Calling the OAuth2 authorization-code flow where every configured callback port is already bound by another process (or blocked by permissions/firewall), so the ServerSocket bind fails for all ports in the list.

Common situations: Parallel test runs colliding on the same fixed callbackPort; a stale previous run's server still holding the port; running multiple suites on one CI host; port <1024 on Unix without privileges; corporate firewall blocking localhost binding in unusual setups.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/b54ec638aa077ea6. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/http/AuthorizationCodeAuthHandler.java:243

     * Start callback server on configured or default ports
     */
    private String startCallbackServer(LocalCallbackServer server) {
        int[] ports = getConfiguredPorts();

        Exception lastException = null;
        for (int port : ports) {
            try {
                String redirectUri = server.start(port);
                logger.debug("Callback server started on port {}", port);
                return redirectUri;
            } catch (Exception e) {
                logger.warn("Port {} in use, trying next port", port);
                lastException = e;
            }
        }

        // If all configured ports fail, provide helpful error message
        throw new OAuth2Exception(
            "Could not start callback server on any configured port: " + java.util.Arrays.toString(ports) + ". " +
            "Please ensure at least one port is available, or configure different ports using 'callbackPort' or 'callbackPorts'. " +
            "These ports must be registered as redirect URIs with your OAuth provider.",
            lastException
        );
    }

    /**
     * Get configured callback ports or use defaults
     */
    private int[] getConfiguredPorts() {
        // Check for single port configuration
        Object callbackPort = config.get("callbackPort");
        if (callbackPort != null) {
            return new int[] { parsePort(callbackPort) };
        }

        // Check for multiple ports configuration

View on GitHub (pinned to a22eb90246)