{"record":{"id":"19fcbef019ef1ca2","repo":"juanfont/headscale","slug":"unknown-field","errorCode":null,"errorMessage":"unknown field","messagePattern":"unknown field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":145,"sourceCode":"\tErrTagNotDefined               = errors.New(\"tag not found\")\n\tErrAutoApproverNotAlias        = errors.New(\"auto approver is not an alias\")\n\tErrInvalidACLAction            = errors.New(\"invalid ACL action\")\n\tErrInvalidSSHAction            = errors.New(\"invalid SSH action\")\n\tErrInvalidProtocolNumber       = errors.New(\"invalid protocol number\")\n\tErrProtocolLeadingZero         = errors.New(\"leading 0 not permitted in protocol number\")\n\tErrProtocolOutOfRange          = errors.New(\"protocol number out of range (0-255)\")\n\tErrAutogroupNotSupported       = errors.New(\"autogroup not supported in headscale\")\n\tErrAutogroupInternetSrc        = errors.New(\"autogroup:internet can only be used in ACL destinations\")\n\tErrAutogroupSelfSrc            = errors.New(\"\\\"autogroup:self\\\" not valid on the src side of a rule\")\n\tErrAutogroupNotSupportedACLSrc = errors.New(\"autogroup not supported for ACL sources\")\n\tErrAutogroupNotSupportedACLDst = errors.New(\"autogroup not supported for ACL destinations\")\n\tErrAutogroupDangerAllDst       = errors.New(\"cannot use autogroup:danger-all as a dst\")\n\tErrAutogroupNotSupportedSSHSrc = errors.New(\"autogroup not supported for SSH sources\")\n\tErrAutogroupNotSupportedSSHDst = errors.New(\"autogroup not supported for SSH destinations\")\n\tErrHostNotDefined              = errors.New(\"host not defined in policy\")\n\tErrSSHSourceAliasNotSupported  = errors.New(\"alias not supported for SSH source\")\n\tErrSSHDestAliasNotSupported    = errors.New(\"alias not supported for SSH destination\")\n\tErrUnknownField                = errors.New(\"unknown field\")\n\tErrProtocolNoSpecificPorts     = errors.New(\"protocol does not support specific ports\")\n\tErrTestEmptyAssertions         = errors.New(\"test entry must have at least one of \\\"accept\\\" or \\\"deny\\\"\")\n\tErrTestProtocolNotAllowed      = errors.New(\"test protocol must be tcp, udp, sctp, or empty\")\n\tErrTestDestinationMultiPort    = errors.New(\"test destination port must be a single port\")\n\tErrTestDestinationCIDR         = errors.New(\"test destination must be a single host, not a CIDR range\")\n\tErrAutogroupInternetTestDst    = errors.New(\"autogroup:internet not valid as a test destination\")\n\tErrSSHTestEmptySrc             = errors.New(\"SSH tests entry must have a non-empty src\")\n\tErrSSHTestEmptyDst             = errors.New(\"SSH tests entry must have at least one dst\")\n\tErrSSHTestDstUnknownTag        = errors.New(\"SSH tests dst contains unknown tag\")\n\tErrSSHTestDstDisallowedElement = errors.New(\"SSH tests dst contains disallowed element\")\n)\n\ntype resolved struct {\n\tips netipx.IPSet\n}\n\nfunc newResolved(ipb *netipx.IPSetBuilder) (resolved, error) {\n\tips, err := ipb.IPSet()","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L127-L163","documentation":"ErrUnknownField is returned by unmarshalPolicy (hscontrol/policy/v2/types.go:3140) when the HuJSON policy parses successfully but JSON unmarshalling into the Policy struct hits a key the struct does not define (encoding/json v2 ErrUnknownName wrapped in a SemanticError). It means the policy file contains a field that headscale's policy schema does not know, so the whole policy is rejected. The message includes the offending field name via JSON pointer's last token.","triggerScenarios":"Loading any policy (config file, ACL HuJSON, or API policy update) that contains a misspelled or unsupported top-level or nested key, e.g. \"acls\" vs the supported \"grants\", \"destPorts\", or a typo like \"tagOwner\". Raised during unmarshalPolicy -> json.Unmarshal(ast.Pack(), &policy) when errors.AsType[*json.SemanticError] finds errors.Is(serr.Err, json.ErrUnknownName).","commonSituations":"Copying an ACL block from Tailscale or old headscale docs into a newer policy format that renamed fields; hand-editing policy HuJSON; upgrading headscale across a policy schema change where a field was renamed/removed; trailing garbage keys left after refactoring a policy.","solutions":["Check the error's quoted field name and locate it in your policy file (search for the exact key)","Rename the key to the current schema's name (see hscontrol/policy/v2/types.go Policy struct fields, e.g. grants, hosts, tagOwners, autoApprovers, tests)","If the key is genuinely unneeded, delete it from the policy","Validate the policy after editing: headscale policy check / reload, or run the policy through the v2 compiler before deploying"],"exampleFix":"// before (policy.hujson)\n{\n  \"acls\": [ ... ]\n}\n// after\n{\n  \"grants\": [ ... ]\n}","handlingStrategy":"try-catch","validationCode":"// Before loading, verify every top-level key against the known set\nvar knownTopLevel = map[string]bool{\"acls\": true, \"grants\": true, \"hosts\": true, \"tagOwners\": true, \"autoApprovers\": true, \"groups\": true, \"tests\": true, \"sshTests\": true, \"nodeAttrs\": true}\nfunc checkTopLevelKeys(t *testing.T, policyHuJSON []byte) {\n    ast, _ := hujson.Parse(policyHujson)\n    // walk top-level literal members and fail on unknown keys\n}","typeGuard":null,"tryCatchPattern":"// When compiling/loading a policy\npol, err := policyv2.CompileHuJSON(buf)\nif err != nil {\n    if errors.Is(err, policyv2.ErrUnknownField) {\n        // err message quotes the bad field; surface it with file+key to the user\n        return fmt.Errorf(\"policy contains unknown field: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep policies in version control and validate them in CI with headscale policy check before deploy","When upgrading headscale, diff your policy against the current example ACL docs for renamed fields","Use the Policy struct fields in hscontrol/policy/v2/types.go as the authoritative schema"],"tags":["policy","hujson","config","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}