{"record":{"id":"e8bc88ab211c9c4b","repo":"hashicorp/terraform","slug":"no-suitable-tcp-ports-between-d-and-d-are-avai","errorCode":null,"errorMessage":"no suitable TCP ports (between %d and %d) are available for the temporary OAuth callback server","messagePattern":"no suitable TCP ports \\(between (.+?) and (.+?)\\) are available for the temporary OAuth callback server","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/login.go","lineNumber":752,"sourceCode":"\t// another.\n\tmaxTries := availCount + (availCount / 2)\n\n\tfor tries := 0; tries < maxTries; tries++ {\n\t\tport := rand.Intn(availCount) + int(minPort)\n\t\taddr := fmt.Sprintf(\"127.0.0.1:%d\", port)\n\t\tlog.Printf(\"[TRACE] login: trying %s as a listen address for temporary OAuth callback server\", addr)\n\t\tl, err := net.Listen(\"tcp4\", addr)\n\t\tif err == nil {\n\t\t\t// We use a path that doesn't end in a slash here because some\n\t\t\t// OAuth server implementations don't allow callback URLs to\n\t\t\t// end with slashes.\n\t\t\tcallbackURL := fmt.Sprintf(\"http://localhost:%d/login\", port)\n\t\t\tlog.Printf(\"[TRACE] login: callback URL will be %s\", callbackURL)\n\t\t\treturn l, callbackURL, nil\n\t\t}\n\t}\n\n\treturn nil, \"\", fmt.Errorf(\"no suitable TCP ports (between %d and %d) are available for the temporary OAuth callback server\", minPort, maxPort)\n}\n\nfunc (c *LoginCommand) proofKey() (key, challenge string, err error) {\n\t// Wel use a UUID-like string as the \"proof key for code exchange\" (PKCE)\n\t// that will eventually authenticate our request to the token endpoint.\n\t// Standard UUIDs are explicitly not suitable as secrets according to the\n\t// UUID spec, but our go-uuid just generates totally random number sequences\n\t// formatted in the conventional UUID syntax, so that concern does not\n\t// apply here: this is just a 128-bit crypto-random number.\n\tuu, err := uuid.GenerateUUID()\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\tkey = fmt.Sprintf(\"%s.%09d\", uu, rand.Intn(999999999))\n\n\th := sha256.New()\n\th.Write([]byte(key))","sourceCodeStart":734,"sourceCodeEnd":770,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/command/login.go#L734-L770","documentation":"Thrown by `LoginCommand.listenerForCallback` after exhausting `maxTries` (150% of the port range size) random attempts to `net.Listen(\"tcp4\", \"127.0.0.1:<port>\")` across the `[minPort, maxPort]` window advertised by the server's OAuth client config. The temporary local HTTP server is needed to receive the OAuth authorization-code redirect. This is a local-resource exhaustion error, not a remote-server error.","triggerScenarios":"Every randomly chosen port in the range returned a non-nil error from `net.Listen`. The range comes from `clientConfig.MinPort`/`clientConfig.MaxPort` discovered via the host's OAuth service descriptor. The loop runs `availCount + availCount/2` times before giving up.","commonSituations":"A development machine with many local services (Docker, other IDEs, preview servers) consuming ephemeral ports; a CI runner with a restricted or crowded port range; security software (endpoint agents) holding or blocking loopback binds; Linux with a narrow `net.ipv4.ip_local_port_range` that excludes the advertised window; another `terraform login` already in flight holding a port.","solutions":["Free loopback ports: stop other local servers / Docker containers / competing `terraform login` processes, then retry.","Raise the OS ephemeral port range (Linux): `sysctl -w net.ipv4.ip_local_port_range=\"10000 65000\"` so more candidates fall inside the advertised window.","Allow the process through endpoint/firewall software that may be blocking loopback TCP binds.","Retry on a different machine or runner where fewer ports are occupied.","If controlling the TFE server, widen the advertised `min_port`/`max_port` in the OAuth client config."],"exampleFix":"# Linux: widen ephemeral port range\nsudo sysctl -w net.ipv4.ip_local_port_range=\"10000 65000\"\n# then retry\nterraform login app.terraform.io","handlingStrategy":"validation","validationCode":"// Check that at least one port in a candidate range is bindable before login.\nfunc freePortAvailable(min, max uint16) bool {\n    for i := 0; i < 50; i++ {\n        p := int(min) + rand.Intn(int(max)-int(min))\n        l, err := net.Listen(\"tcp4\", fmt.Sprintf(\"127.0.0.1:%d\", p))\n        if err == nil { l.Close(); return true }\n    }\n    return false\n}","typeGuard":"null","tryCatchPattern":"// net.Listen errors are not retried inside listenerForCallback beyond maxTries;\n// callers cannot retry meaningfully. Surface the error and advise freeing ports.","preventionTips":["Keep the OS ephemeral port range wide on dev/CI machines.","Avoid running many concurrent `terraform login` / local servers.","Allow loopback TCP binds in endpoint-security software."],"tags":["terraform","login","oauth","network","tcp","ports","loopback"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}