{"record":{"id":"b75332c98a23df4c","repo":"juanfont/headscale","slug":"unsupported-policy-mode","errorCode":null,"errorMessage":"unsupported policy mode","messagePattern":"unsupported policy mode","errorType":"validation","errorClass":"ErrUnsupportedPolicyMode","httpStatus":null,"severity":"error","filePath":"hscontrol/state/state.go","lineNumber":66,"sourceCode":"\n\t// defaultRegisterCacheMaxEntries is the default upper bound on the number\n\t// of pending registration entries the auth cache will hold. With a 15-minute\n\t// TTL and a stripped-down RegistrationData payload (~200 bytes per entry),\n\t// 1024 entries cap the worst-case cache footprint at well under 1 MiB even\n\t// under sustained unauthenticated cache-fill attempts.\n\tdefaultRegisterCacheMaxEntries = 1024\n\n\t// defaultNodeStoreBatchSize is the default number of write operations to batch\n\t// before rebuilding the in-memory node snapshot.\n\tdefaultNodeStoreBatchSize = 100\n\n\t// defaultNodeStoreBatchTimeout is the default maximum time to wait before\n\t// processing a partial batch of node operations.\n\tdefaultNodeStoreBatchTimeout = 500 * time.Millisecond\n)\n\n// ErrUnsupportedPolicyMode is returned for invalid policy modes. Valid modes are \"file\" and \"db\".\nvar ErrUnsupportedPolicyMode = errors.New(\"unsupported policy mode\")\n\n// ErrNodeNotFound is returned when a node cannot be found by its ID.\nvar ErrNodeNotFound = errors.New(\"node not found\")\n\n// ErrInvalidNodeView is returned when an invalid node view is provided.\nvar ErrInvalidNodeView = errors.New(\"invalid node view provided\")\n\n// ErrNodeNotInNodeStore is returned when a node no longer exists in the [NodeStore].\nvar ErrNodeNotInNodeStore = errors.New(\"node no longer exists in NodeStore\")\n\n// ErrNodeNameNotUnique is returned when a node name is not unique.\nvar ErrNodeNameNotUnique = errors.New(\"node name is not unique\")\n\n// nodeUpdateColumns lists all Node columns that should be written\n// during a struct-based GORM Updates() call.  Listing them explicitly\n// forces GORM to include nil/zero-value fields (e.g. UserID=nil when\n// converting a user-owned node to tagged) that struct-based Updates()\n// would otherwise silently skip.","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/state/state.go#L48-L84","documentation":"ErrUnsupportedPolicyMode is a sentinel error in hscontrol/state declaring that the configured policy mode is neither \"file\" nor \"db\". It is produced by wrapping with the offending mode string (hscontrol/state/debug.go:213: fmt.Errorf(\"%w: %s\", ErrUnsupportedPolicyMode, s.cfg.Policy.Mode)). It surfaces during server startup / debug dumps when the policy.mode config value cannot be mapped to a policy manager backend.","triggerScenarios":"Setting policy.mode in the headscale config to anything other than \"file\" or \"db\" (e.g. \"database\", \"acl\", typo like \"filE\"), then triggering the code path in hscontrol/state/debug.go:213 that formats the active policy for a debug dump.","commonSituations":"Upgrading from older headscale versions where policy config keys changed; copy-pasting configs from tutorials that use invalid mode names; leaving a placeholder value in policy.mode.","solutions":["Set policy.mode to \"file\" if the ACL policy lives in a HuJSON/JSON file referenced by policy.path","Set policy.mode to \"db\" if policies are managed via the API/database","Verify there is no YAML typo or stray whitespace in the policy.mode value","After fixing, restart headscale and confirm startup logs no longer report the error"],"exampleFix":"# before\npolicy:\n  mode: database\n\n# after\npolicy:\n  mode: db","handlingStrategy":"validation","validationCode":"validModes := map[string]bool{\"file\": true, \"db\": true}\nif !validModes[cfg.Policy.Mode] {\n    return fmt.Errorf(\"invalid policy mode %q: use file or db\", cfg.Policy.Mode)\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Validate policy.mode against {file, db} in config linting or CI before deploying","Pin config templates reviewed on headscale version upgrades since policy keys have changed across releases"],"tags":["headscale","config","policy","startup"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}