{"record":{"id":"3f85c1a093d1a655","repo":"juanfont/headscale","slug":"parsing-s-w","errorCode":null,"errorMessage":"parsing %s: %w","messagePattern":"parsing (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"hscontrol/noise.go","lineNumber":355,"sourceCode":"\nfunc stringParam(req *http.Request, key string) (string, error) {\n\tparam := chi.URLParam(req, key)\n\tif param == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: %s\", ErrMissingURLParameter, key)\n\t}\n\n\treturn param, nil\n}\n\nfunc nodeIDParam(req *http.Request, key string) (types.NodeID, error) {\n\tparam := chi.URLParam(req, key)\n\tif param == \"\" {\n\t\treturn 0, fmt.Errorf(\"%w: %s\", ErrMissingURLParameter, key)\n\t}\n\n\tid, err := types.ParseNodeID(param)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"parsing %s: %w\", key, err)\n\t}\n\n\treturn id, nil\n}\n\n// SSHActionHandler handles the /ssh-action endpoint, returning a\n// [tailcfg.SSHAction] to the client with the verdict of an SSH access\n// request.\nfunc (ns *noiseServer) SSHActionHandler(\n\twriter http.ResponseWriter,\n\treq *http.Request,\n) {\n\tsrcNodeID, err := nodeIDParam(req, \"src_node_id\")\n\tif err != nil {\n\t\thttpError(writer, NewHTTPError(\n\t\t\thttp.StatusBadRequest,\n\t\t\t\"Invalid src_node_id\",\n\t\t\terr,","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/noise.go#L337-L373","documentation":"Returned by nodeIDParam when the URL segment is present but types.ParseNodeID rejects it — the value is not a valid positive integer node ID. The wrapped parse error includes the offending value.","triggerScenarios":"Passing a non-numeric node ID segment, e.g. /machine/ssh/action/abc/to/5, or a negative/zero value where a node ID is required.","commonSituations":"Manually invoking Noise API endpoints for debugging; a client bug that puts a node key or hostname where a numeric node ID belongs; URL templates substituted with the wrong variable.","solutions":["Use the numeric node ID from 'headscale nodes list' or the MapResponse peer list","Check the wrapped error for the exact value that failed to parse","Fix URL construction so the ID segment is the integer node ID, not a key or name"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isValidNodeID(s string) bool {\n    _, err := types.ParseNodeID(s)\n    return err == nil\n}","tryCatchPattern":"id, err := types.ParseNodeID(param)\nif err != nil {\n    return fmt.Errorf(\"parsing node id %q: %w\", param, err)\n}","preventionTips":["Always fetch node IDs from the API/MapResponse rather than deriving them from names or keys","Validate user-supplied ID segments before building request URLs"],"tags":["noise","node-id","validation","parsing"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}