{"record":{"id":"d23a0ae3c812896d","repo":"slackhq/nebula","slug":"nil-byte-array","errorCode":null,"errorMessage":"nil byte array","messagePattern":"nil byte array","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/cert_v1.go","lineNumber":404,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn b, nil\n}\n\nfunc (c *certificateV1) setSignature(b []byte) error {\n\tif len(b) == 0 {\n\t\treturn ErrEmptySignature\n\t}\n\tc.signature = b\n\treturn nil\n}\n\n// unmarshalCertificateV1 will unmarshal a protobuf byte representation of a nebula cert\n// if the publicKey is provided here then it is not required to be present in `b`\nfunc unmarshalCertificateV1(b []byte, publicKey []byte) (*certificateV1, error) {\n\tif len(b) == 0 {\n\t\treturn nil, fmt.Errorf(\"nil byte array\")\n\t}\n\tvar rc RawNebulaCertificate\n\terr := proto.Unmarshal(b, &rc)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rc.Details == nil {\n\t\treturn nil, fmt.Errorf(\"encoded Details was nil\")\n\t}\n\n\tif len(rc.Details.Ips)%2 != 0 {\n\t\treturn nil, fmt.Errorf(\"encoded IPs should be in pairs, an odd number was found\")\n\t}\n\n\tif len(rc.Details.Subnets)%2 != 0 {\n\t\treturn nil, fmt.Errorf(\"encoded Subnets should be in pairs, an odd number was found\")\n\t}","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/cert_v1.go#L386-L422","documentation":"unmarshalCertificateV1 refuses to decode an empty protobuf byte slice; there is nothing to unmarshal so it returns 'nil byte array' immediately. This fails fast before attempting protobuf parsing so callers get a clear message instead of a generic proto error.","triggerScenarios":"Passing an empty (len==0) byte slice to unmarshalCertificateV1 via Recombine, unmarshalCertificateBlock, or directly; e.g. a zero-byte certificate file, an empty protobuf field, or a helper returning no bytes.","commonSituations":"Certificate file truncated to zero bytes on disk; failed read treated as success; empty value pulled from a key-value store; a nil/empty raw certificate field in a bundle being recombined.","solutions":["Check len(b) > 0 before calling unmarshalCertificateV1 and surface a caller-appropriate error","Fix the upstream read (file, network, KV) that produced empty bytes; check read errors","Re-obtain or re-issue the certificate if the source data is genuinely empty","Add logging of the byte-slice source path/key to find why it is empty"],"exampleFix":"// before\nif len(rawCert) == 0 {\n    // silently calls unmarshal, gets 'nil byte array'\n}\nc, err := unmarshalCertificateV1(rawCert, nil)\n// after\nif len(rawCert) == 0 {\n    return nil, fmt.Errorf(\"certificate data from %s is empty\", certPath)\n}\nc, err := unmarshalCertificateV1(rawCert, nil)","handlingStrategy":"validation","validationCode":"if len(rawCertBytes) == 0 {\n    return nil, fmt.Errorf(\"certificate source %s produced no bytes\", source)\n}\nc, err := unmarshalCertificateV1(rawCertBytes, nil)","typeGuard":"func hasCertBytes(b []byte) bool { return len(b) > 0 }","tryCatchPattern":"c, err := unmarshalCertificateV1(rawCertBytes, nil)\nif err != nil {\n    if strings.Contains(err.Error(), \"nil byte array\") {\n        return nil, fmt.Errorf(\"certificate data is empty; check the source read\")\n    }\n    return nil, err\n}","preventionTips":["Check the error return of every file/network read feeding the cert bytes","Validate non-empty certificate data at config-load time","Alert on zero-byte certificate files on disk","Wrap unmarshalCertificateV1 with a helper that enriches empty-input errors"],"tags":["certificate","unmarshal","empty-input"],"backgroundTag":"empty-certificate-data","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}