ory/hydra · error
could not start debug server on port %d: %w
Error message
could not start debug server on port %d: %w
What it means
The perform device flow command in cmd/cmd_perform_device_flow.go starts a local debug HTTP server; this error is returned when net.Listen on 127.0.0.1:<port> fails. It wraps the underlying OS error (typically address already in use or permission denied).
Source
Thrown at cmd/cmd_perform_device_flow.go:46
)
func NewPerformDeviceCodeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "device-code",
Example: "{{ .CommandPath }} --client-id ...",
Short: "Example OAuth 2.0 Client performing the OAuth 2.0 Device Code Flow",
Long: `Performs the device code flow. Useful for getting an access token and an ID token in machines without a browser.
The client that will be used MUST use the "none" or "client_secret_post" token-endpoint-auth-method.`,
RunE: func(cmd *cobra.Command, args []string) error {
client, endpoint, err := cliclient.NewClient(cmd)
if err != nil {
return err
}
if port := flagx.MustGetInt(cmd, "port"); port >= 0 {
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
return fmt.Errorf("could not start debug server on port %d: %w", port, err)
}
srv := http.Server{Handler: newDeviceSrv(client)}
go func() {
if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Debug server error: %v\n", err)
}
}()
defer srv.Close() //nolint:errcheck
}
endpoint = cliclient.GetOAuth2URLOverride(cmd, endpoint)
ctx := context.WithValue(cmd.Context(), oauth2.HTTPClient, client)
scopes := flagx.MustGetStringSlice(cmd, "scope")
deviceAuthUrl := flagx.MustGetString(cmd, "device-auth-url")
tokenUrl := flagx.MustGetString(cmd, "token-url")
audience := flagx.MustGetStringSlice(cmd, "audience")
View on GitHub (pinned to 4174065ffb)
Solutions
- Pick a different free port, e.g. --port 4446
- Find and stop the process holding the port: lsof -i :<port> or ss -ltnp
- Use a port >= 1024 if running unprivileged
- Check that 127.0.0.1 loopback is available (containers/network namespaces)
Example fix
// before hydra perform device flow --port 8080 // after hydra perform device flow --port 8081 # 8080 was occupied
Defensive patterns
Strategy: validation
Validate before calling
port := flagx.MustGetInt(cmd, "port")
if ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)); err != nil {
return fmt.Errorf("port %d unavailable: %w", port, err)
} else { ln.Close() } Try / catch
if err != nil {
fmt.Fprintf(os.Stderr, "port %d busy (%v): stop the other process or pick another port\n", port, err)
os.Exit(1)
} Prevention
- Reserve debug ports per developer/tool
- Add pre-flight port checks in scripts
- Use ephemeral high ports
When it happens
Trigger: Running `hydra perform device flow --port N` where port N is already bound by another process, or N is a privileged port (<1024) without permissions, or the loopback interface is unavailable.
Common situations: Previous debug server instance still running and holding the port, another dev service (webpack, vite) on the same port, running with --port 80 in a non-root container.
Related errors
- command expects one argument which is the path to the output
- DNS lookup timed out
- no route to host
- A DSN is required as a positional argument when not passing
- Janitor requires at least one of --tokens, --requests or --g
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/b6afe2530f6b50e2.
Report an issue: GitHub.