{"record":{"id":"e308d66b5403e798","repo":"juanfont/headscale","slug":"pkce-method-must-be-either-plain-or-s256","errorCode":null,"errorMessage":"pkce.method must be either 'plain' or 'S256'","messagePattern":"pkce\\.method must be either 'plain' or 'S256'","errorType":"validation","errorClass":"errInvalidPKCEMethod","httpStatus":null,"severity":"error","filePath":"hscontrol/types/config.go","lineNumber":41,"sourceCode":"\t\"tailscale.com/types/dnstype\"\n\t\"tailscale.com/util/set\"\n)\n\nconst (\n\tPKCEMethodPlain string = \"plain\"\n\tPKCEMethodS256  string = \"S256\"\n\n\tdefaultNodeStoreBatchSize = 100\n)\n\nvar (\n\terrOidcMutuallyExclusive     = errors.New(\"oidc_client_secret and oidc_client_secret_path are mutually exclusive\")\n\terrOIDCIssuerInvalid         = errors.New(\"oidc.issuer must be a valid http(s) URL\")\n\terrOIDCClientIDRequired      = errors.New(\"oidc.client_id is required when oidc.issuer is set\")\n\terrOIDCClientSecretRequired  = errors.New(\"oidc.client_secret or oidc.client_secret_path is required when oidc.issuer is set\")\n\terrServerURLSuffix           = errors.New(\"server_url cannot be part of base_domain in a way that could make the DERP and headscale server unreachable\")\n\terrServerURLSame             = errors.New(\"server_url cannot use the same domain as base_domain in a way that could make the DERP and headscale server unreachable\")\n\terrInvalidPKCEMethod         = errors.New(\"pkce.method must be either 'plain' or 'S256'\")\n\terrTrustedProxyZeroRange     = errors.New(\"0.0.0.0/0 and ::/0 are not allowed\")\n\tErrNoPrefixConfigured        = errors.New(\"no IPv4 or IPv6 prefix configured, minimum one prefix is required\")\n\tErrInvalidAllocationStrategy = errors.New(\"invalid prefix allocation strategy\")\n)\n\ntype IPAllocationStrategy string\n\nconst (\n\tIPAllocationStrategySequential IPAllocationStrategy = \"sequential\"\n\tIPAllocationStrategyRandom     IPAllocationStrategy = \"random\"\n)\n\ntype PolicyMode string\n\nconst (\n\tPolicyModeDB   = \"database\"\n\tPolicyModeFile = \"file\"\n)","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/types/config.go#L23-L59","documentation":"errInvalidPKCEMethod is an unexported config validation error in hscontrol/types/config.go:41 returned at config.go:363 when oidc.pkce.method is set to anything other than 'plain' or 'S256' (the PKCEMethodPlain/PKCEMethodS256 constants). The same concept has a runtime twin in hscontrol/oidc.go:58 used when an OIDC flow gets an unsupported method at request time.","triggerScenarios":"Setting oidc.pkce.method to values like 's256', 'SHA256', 'none', or leaving typos in the config; validation runs at config load (config.go:363) and fails startup; covered by config_test.go:444.","commonSituations":"IdP docs using different casing; copy-pasting from examples with 's256' lowercase; uncommenting a placeholder pkce block without editing it.","solutions":["Set oidc.pkce.method to 'S256' (recommended, widely supported)","Use 'plain' only if the IdP lacks S256 support","Match the exact casing and spelling; no other values are accepted","Restart headscale after correcting the config"],"exampleFix":"# before\noidc:\n  pkce:\n    method: s256\n\n# after\noidc:\n  pkce:\n    method: S256","handlingStrategy":"validation","validationCode":"valid := map[string]bool{\"plain\": true, \"S256\": true}\nif !valid[cfg.OIDC.PKCE.Method] {\n    return errors.New(\"pkce.method must be plain or S256\")\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Default to S256 and match spelling/casing exactly","Ling config templates for lowercase 's256' typos before deploying"],"tags":["headscale","config","oidc","pkce","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}