{"record":{"id":"957ed3e08074747f","repo":"tailscale/tailscale","slug":"incorrect-len-for-nodepublic-d-d","errorCode":null,"errorMessage":"incorrect len for NodePublic (%d != %d)","messagePattern":"incorrect len for NodePublic \\((.+?) != (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"types/key/node.go","lineNumber":355,"sourceCode":"\treturn parseHex(k.k[:], mem.B(b), mem.S(nodePublicHexPrefix))\n}\n\n// MarshalBinary implements encoding.BinaryMarshaler.\nfunc (k NodePublic) MarshalBinary() (data []byte, err error) {\n\tb := make([]byte, len(nodePublicBinaryPrefix)+NodePublicRawLen)\n\tcopy(b[:len(nodePublicBinaryPrefix)], nodePublicBinaryPrefix)\n\tcopy(b[len(nodePublicBinaryPrefix):], k.k[:])\n\treturn b, nil\n}\n\n// UnmarshalBinary implements encoding.BinaryUnmarshaler.\nfunc (k *NodePublic) UnmarshalBinary(in []byte) error {\n\tdata := mem.B(in)\n\tif !mem.HasPrefix(data, mem.S(nodePublicBinaryPrefix)) {\n\t\treturn fmt.Errorf(\"missing/incorrect type prefix %s\", nodePublicBinaryPrefix)\n\t}\n\tif want, got := len(nodePublicBinaryPrefix)+NodePublicRawLen, data.Len(); want != got {\n\t\treturn fmt.Errorf(\"incorrect len for NodePublic (%d != %d)\", got, want)\n\t}\n\n\tdata.SliceFrom(len(nodePublicBinaryPrefix)).Copy(k.k[:])\n\treturn nil\n}\n\n// WireGuardGoString prints k in the same format used by wireguard-go.\nfunc (k NodePublic) WireGuardGoString() string {\n\t// This implementation deliberately matches the overly complicated\n\t// implementation in wireguard-go.\n\tb64 := func(input byte) byte {\n\t\treturn input + 'A' + byte(((25-int(input))>>8)&6) - byte(((51-int(input))>>8)&75) - byte(((61-int(input))>>8)&15) + byte(((62-int(input))>>8)&3)\n\t}\n\tb := []byte(\"peer(____…____)\")\n\tconst first = len(\"peer(\")\n\tconst second = len(\"peer(____…\")\n\tb[first+0] = b64((k.k[0] >> 2) & 63)\n\tb[first+1] = b64(((k.k[0] << 4) | (k.k[1] >> 4)) & 63)","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/types/key/node.go#L337-L373","documentation":"NodePublic.UnmarshalBinary accepts the binary prefix but the remaining payload length differs from NodePublicRawLen (the two %d values show got vs want). The blob is truncated, padded, or a different key size, so it cannot be copied into the fixed 32-byte field.","triggerScenarios":"Thrown at types/key/node.go:355 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Re-serialize the key with MarshalBinary so the payload is exactly the fixed raw length","Verify storage/transport did not truncate the blob (check lengths before calling UnmarshalBinary)","Treat mismatched lengths as corrupt data: discard and re-fetch the trusted key material"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}