{"record":{"id":"af466bd831a0100d","repo":"cilium/cilium","slug":"invalid-cipher-ipsec-key-spi-s","errorCode":null,"errorMessage":"invalid cipher IPsec key SPI: %s","messagePattern":"invalid cipher IPsec key SPI: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cilium-cli/encrypt/ipsec_rotate_key.go","lineNumber":118,"sourceCode":"\t\treturn ipsecKey{}, fmt.Errorf(\"invalid IPsec key size: %s\", parts[4])\n\t}\n\tkey := ipsecKey{\n\t\tspi:  spi,\n\t\talgo: parts[2],\n\t\tkey:  parts[3],\n\t\tsize: size,\n\t}\n\treturn key, nil\n}\n\nfunc cipherKeyFromSlice(parts []string) (ipsecKey, error) {\n\tif len(parts) != 6 {\n\t\treturn ipsecKey{}, fmt.Errorf(\"IPsec key invalid [expected parts: 6, actual parts: %d]\", len(parts))\n\t}\n\tparts[1] = strings.TrimSuffix(parts[1], \"+\")\n\tspi, err := strconv.Atoi(parts[1])\n\tif err != nil {\n\t\treturn ipsecKey{}, fmt.Errorf(\"invalid cipher IPsec key SPI: %s\", parts[1])\n\t}\n\tkey := ipsecKey{\n\t\tspi:        spi,\n\t\talgo:       parts[2],\n\t\tkey:        parts[3],\n\t\tcipherMode: parts[4],\n\t\tcipherKey:  parts[5],\n\t}\n\treturn key, nil\n}\n\nconst maxIPsecSPI = 16\n\nfunc (k ipsecKey) rotate() (ipsecKey, error) {\n\tkey, err := generateRandomHex(len(k.key))\n\tif err != nil {\n\t\treturn ipsecKey{}, fmt.Errorf(\"failed to generate authentication key: %w\", err)\n\t}","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/cilium-cli/encrypt/ipsec_rotate_key.go#L100-L136","documentation":"cipherKeyFromSlice converts field 2 (index 1, the SPI with a trailing '+' trimmed) to an integer for 6-field cipher-mode key lines. This error means the SPI token is not a valid decimal number.","triggerScenarios":"The first field pair of a cipher key line is malformed: e.g. 'abc+ hmac-sha256 ...' or 'hmac-sha256 rfc4106(gcm(aes)) ...' with the SPI field missing/shifted, so Atoi fails after trimming '+'.","commonSituations":"Corrupted or hand-edited cipher key secrets; field order mistakes when constructing 6-field keys manually (someone put the algorithm first); partial paste that dropped the SPI.","solutions":["Ensure field 2 is a decimal SPI, optionally ending in '+' (e.g. '15+'); fix the token or field order.","Validate the full 6-field layout: spi, auth-algo, auth-key, cipher-mode, cipher-key, size.","Regenerate the key entry with Cilium's cipher key format and update the secret before rotating."],"exampleFix":"// before\n\"hmac-sha256 abcdef rfc4106(gcm(aes)) 0123456789abcdef 128\" // SPI missing\n// after\n\"15+ hmac-sha256 abcdef rfc4106(gcm(aes)) 0123456789abcdef 128\"","handlingStrategy":"validation","validationCode":"parts := strings.Fields(keyLine)\nif len(parts) != 6 {\n    return fmt.Errorf(\"expected 6 fields, got %d\", len(parts))\n}\nif _, err := strconv.Atoi(strings.TrimSuffix(parts[1], \"+\")); err != nil {\n    return fmt.Errorf(\"field 2 must be numeric SPI, got %q\", parts[1])\n}","typeGuard":"func validCipherKeyLine(line string) bool {\n    parts := strings.Fields(line)\n    if len(parts) != 6 { return false }\n    _, err := strconv.Atoi(strings.TrimSuffix(parts[1], \"+\"))\n    return err == nil\n}","tryCatchPattern":"key, err := cipherKeyFromSlice(parts)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid cipher IPsec key SPI\") {\n        // fix SPI token/field order and retry\n    }\n    return err\n}","preventionTips":["Keep SPI as the first field: decimal, optional trailing '+'","Follow exact 6-field order: spi, auth-algo, auth-key, cipher-mode, cipher-key, size","Validate cipher key lines before storing in the secret"],"tags":["cilium","ipsec","key-rotation","parsing"],"backgroundTag":"ipsec-key-format-invalid","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}