{"record":{"id":"b6b74ced120bee3d","repo":"juanfont/headscale","slug":"w-t","errorCode":null,"errorMessage":"%w: %T","messagePattern":"%w: %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":912,"sourceCode":"\t\t\t\t)\n\t\t\t}\n\n\t\t\tve.Ports = ports\n\t\t} else {\n\t\t\treturn ErrHostportMissingColon\n\t\t}\n\n\t\tve.Alias, err = parseAlias(vs)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := ve.Validate(); err != nil { //nolint:noinlineerr\n\t\t\treturn err\n\t\t}\n\n\tdefault:\n\t\treturn fmt.Errorf(\"%w: %T\", ErrTypeNotSupported, vs)\n\t}\n\n\treturn nil\n}\n\n// ProtocolPort is a representation of the \"network layer capabilities\"\n// of a Grant.\ntype ProtocolPort struct {\n\tPorts    []tailcfg.PortRange\n\tProtocol Protocol\n}\n\nfunc (ve *ProtocolPort) UnmarshalJSON(b []byte) error {\n\tvar v any\n\n\terr := json.Unmarshal(b, &v)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":894,"sourceCodeEnd":930,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L894-L930","documentation":"The destination unmarshaller received a JSON value of an unsupported type (anything other than string — number, bool, object, array). Go's type switch has no case for it, so it fails with ErrTypeNotSupported and the concrete Go type name (%T).","triggerScenarios":"A test destination written as a JSON number ({\"accept\": [80]}), a boolean, or a nested object. The type switch in the destination unmarshaller falls through to default.","commonSituations":"Quotes lost when editing HuJSON (bare numeric destination); YAML-to-HuJSON conversion emitting non-string scalars; hand-built map[string]interface{} policies passed to the unmarshaller.","solutions":["Quote every destination: \"80\" or better \"web:80\", never bare 80.","Fix converters to always emit strings for destination entries.","When building policies programmatically, use string values only."],"exampleFix":"// before\n\"accept\": [80]\n\n// after\n\"accept\": [\"web:80\"]","handlingStrategy":"type-guard","validationCode":"// Ensure the JSON value is a string before unmarshalling.\nif raw[0] != '\"' {\n    return fmt.Errorf(\"destination must be a JSON string, got: %s\", raw)\n}","typeGuard":"func isDestinationString(v any) bool {\n    _, ok := v.(string)\n    return ok\n}","tryCatchPattern":"if err := json.Unmarshal(data, &dst); err != nil {\n    if errors.Is(err, v2.ErrTypeNotSupported) {\n        // %T in the message reveals the offending Go type; quote the value\n    }\n    return err\n}","preventionTips":["Always quote destinations in HuJSON/JSON.","Check converter output for bare scalars.","Programmatic policies: only strings in destination fields."],"tags":["policy","acl","json","type-error","configuration","go"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}