{"record":{"id":"19cece66aa0493b8","repo":"juanfont/headscale","slug":"not-confirmed-aborting","errorCode":null,"errorMessage":"not confirmed, aborting","messagePattern":"not confirmed, aborting","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"hscontrol/api/v1/nodes.go","lineNumber":25,"sourceCode":"\t\"net/netip\"\n\t\"slices\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/danielgtaylor/huma/v2\"\n\t\"github.com/juanfont/headscale/hscontrol/types\"\n\t\"github.com/juanfont/headscale/hscontrol/util\"\n\t\"tailscale.com/net/tsaddr\"\n\t\"tailscale.com/tailcfg\"\n\t\"tailscale.com/types/key\"\n)\n\nfunc init() {\n\tregistrations = append(registrations, registerNodes)\n}\n\n// errBackfillNotConfirmed guards BackfillNodeIPs behind explicit confirmed=true.\nvar errBackfillNotConfirmed = errors.New(\"not confirmed, aborting\")\n\n// registerMethodToV1Enum maps the stored register method onto the\n// SCREAMING_SNAKE enum string the v1 contract emits.\nvar registerMethodToV1Enum = map[string]string{\n\tutil.RegisterMethodAuthKey: \"REGISTER_METHOD_AUTH_KEY\",\n\tutil.RegisterMethodOIDC:    \"REGISTER_METHOD_OIDC\",\n\tutil.RegisterMethodCLI:     \"REGISTER_METHOD_CLI\",\n}\n\n// Node mirrors the v1 Node message. The protojson contract emits unpopulated\n// fields: scalars and slices always (no omitempty), nested messages and optional\n// timestamps as JSON null when unset.\ntype Node struct {\n\tID              string          `format:\"uint64\"                                                                                      json:\"id\"`\n\tMachineKey      string          `json:\"machineKey\"`\n\tNodeKey         string          `json:\"nodeKey\"`\n\tDiscoKey        string          `json:\"discoKey\"`\n\tIPAddresses     []string        `json:\"ipAddresses\"                                                                                   nullable:\"false\"`","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/api/v1/nodes.go#L7-L43","documentation":"Error (with body and redirectURL returned) from doLoginURLWithClient when followRedirects is true but the final status is not 200: the login flow followed redirects and landed on a non-OK page — meaning login did not complete (error page, 4xx/5xx after redirect, or a 3xx that was followed to something unexpected).","triggerScenarios":"OIDC interactive login where after following redirects the server returns an error page (401/403/500), or the flow ends on a redirect target that is not the success page.","commonSituations":"OIDC provider rejecting the client (bad client_id/secret), headscale OIDC callback mismatch (redirect URI not registered), expired nonce/state, or the interstitial confirmation step not completed.","solutions":["Read the logged body (it is log.Printf'd) to see the provider's error message.","Verify OIDC config: client_id, client_secret, redirect URL matching headscale's /oidc/callback.","Check headscale and provider logs for the failing exchange.","Confirm the flow accounts for the confirmation interstitial (see submitConfirmForm) if the deployment renders one."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"body, redir, err := doLoginURLWithClient(hostname, loginURL, hc, true)\nif err != nil {\n    if strings.Contains(err.Error(), \"unexpected status code\") {\n        // body and redir are populated; log them and inspect provider state\n        log.Printf(\"login failed, body=%s redirect=%v\", body, redir)\n    }\n    return err\n}","preventionTips":["Keep OIDC client credentials and redirect URIs correct and in sync with headscale config.","Log the returned body on failure; it almost always names the cause.","Handle the confirmation interstitial step where the deployment renders one."],"tags":["integration","http","oidc","login","status-code"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}