{"record":{"id":"a0c1f4c417c62331","repo":"juanfont/headscale","slug":"is-above-the-max-168h","errorCode":null,"errorMessage":"is above the max (168h)","messagePattern":"is above the max \\(168h\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":47,"sourceCode":"\tjson.DefaultOptionsV2(),\n\tjson.MatchCaseInsensitiveNames(true),\n\tjson.RejectUnknownMembers(true),\n}\n\nconst Wildcard = Asterix(0)\n\nvar ErrAutogroupSelfRequiresPerNodeResolution = errors.New(\"autogroup:self requires per-node resolution and cannot be resolved in this context\")\n\nvar ErrUndefinedTagReference = errors.New(\"references undefined tag\")\n\n// SSH validation errors.\nvar (\n\tErrSSHTagSourceToUserDest             = errors.New(\"tags in SSH source cannot access user-owned devices\")\n\tErrSSHUserDestRequiresSameUser        = errors.New(\"user destination requires source to contain only that same user\")\n\tErrSSHAutogroupSelfRequiresUserSource = errors.New(\"autogroup:self destination requires source to contain only users or groups, not tags or autogroup:tagged\")\n\tErrSSHTagSourceToAutogroupMember      = errors.New(\"tags in SSH source cannot access autogroup:member (user-owned devices)\")\n\tErrSSHWildcardDestination             = errors.New(\"wildcard (*) is not supported as SSH destination\")\n\tErrSSHCheckPeriodAboveMax             = errors.New(\"is above the max (168h)\")\n\tErrSSHCheckPeriodNegative             = errors.New(\"must be a positive duration\")\n\tErrSSHCheckPeriodOnNonCheck           = errors.New(\"checkPeriod is only valid with action \\\"check\\\"\")\n\tErrInvalidLocalpart                   = errors.New(\"invalid localpart format, must be localpart:*@<domain>\")\n\tErrSSHUsersMustBeSpecified            = errors.New(\"users must be specified\")\n\tErrSSHUserInvalid                     = errors.New(\"is not valid\")\n\tErrSSHAcceptEnvEmpty                  = errors.New(\"acceptEnv values cannot be empty\")\n\tErrSSHActionMustBeSpecified           = errors.New(\"action must be specified\")\n\tErrSSHActionInvalid                   = errors.New(\"is not a valid action\")\n\tErrSSHDestinationHostAlias            = errors.New(\"invalid dst\")\n\tErrTagNameMustStartWithLetter         = errors.New(\"tag names must start with a letter, after 'tag:'\")\n\tErrGroupMembersCannotBeRecursive      = errors.New(\"group members cannot be recursive\")\n)\n\n// SSH check period constants per Tailscale docs:\n// https://tailscale.com/docs/features/tailscale-ssh#checkperiod\n// SaaS imposes no minimum (0s is accepted) so headscale matches.\nconst (\n\tSSHCheckPeriodDefault = 12 * time.Hour","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L29-L65","documentation":"SSH validation error (hscontrol/policy/v2/types.go:2863, formatted as 'checkPeriod <dur> is above the max (168h)'): an SSH rule with action \"check\" specifies a checkPeriod longer than 7 days (168h). Tailscale caps re-check intervals so periodic SSH re-authentication cannot be effectively disabled by a huge period.","triggerScenarios":"{\"action\": \"check\", \"checkPeriod\": \"720h\"} or any duration > 168h; types_test.go:4490-4615 exercises exactly these boundary cases. Also triggered by unit-less values parsed as hours depending on the duration format accepted.","commonSituations":"Trying to make check 'once a quarter' to avoid prompts; typo adding a zero (720h vs 72h); migrating configs from tooling that did not enforce the cap.","solutions":["Lower checkPeriod to at most \"168h\"","If the intent was 'never re-check', use action \"accept\" instead — but prefer short check periods for least privilege","Automate the re-auth prompt acceptance rather than stretching the period"],"exampleFix":"// before\n{\"src\": [\"group:ops\"], \"dst\": [\"tag:server\"], \"users\": [\"root\"], \"action\": \"check\", \"checkPeriod\": \"720h\"}\n\n// after\n{\"src\": [\"group:ops\"], \"dst\": [\"tag:server\"], \"users\": [\"root\"], \"action\": \"check\", \"checkPeriod\": \"168h\"}","handlingStrategy":"validation","validationCode":"func checkPeriodValid(d time.Duration) bool { return d > 0 && d <= 168*time.Hour }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Cap checkPeriod at 168h in policy generation tooling","Prefer shorter periods; use 'accept' only deliberately","Unit-test duration parsing boundary values (see types_test.go:4490)"],"tags":["policy","ssh","validation","config","headscale"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}