cilium/cilium · error
IPsec key has unsupported format
Error message
IPsec key has unsupported format
What it means
ipsecKeyFromString returns this when the key string from the secret matches none of the registered ipsecParsers regexes. The CLI supports a fixed set of IPsec key string layouts; anything else is rejected before parsing.
Source
Thrown at cilium-cli/encrypt/ipsec_rotate_key.go:86
return fmt.Sprintf("%d%s %s %s %s %s", k.spi, spiSuffix, k.algo, k.key, k.cipherMode, k.cipherKey)
}
var (
ipsecKeyRegex = regexp.MustCompile(`^([[:digit:]]+\+?)[[:space:]](\S+)[[:space:]]([[:alnum:]]+)[[:space:]]([[:digit:]]+)$`)
cipherIPsecKeyRegex = regexp.MustCompile(`^([[:digit:]]+\+?)[[:space:]](\S+)[[:space:]]([[:alnum:]]+)[[:space:]](\S+)[[:space:]]([[:alnum:]]+)$`)
ipsecParsers = map[*regexp.Regexp]func([]string) (ipsecKey, error){
ipsecKeyRegex: keyFromSlice,
cipherIPsecKeyRegex: cipherKeyFromSlice,
}
)
func ipsecKeyFromString(s string) (ipsecKey, error) {
for matcher, parser := range ipsecParsers {
if matcher.MatchString(s) {
return parser(matcher.FindStringSubmatch(s))
}
}
return ipsecKey{}, fmt.Errorf("IPsec key has unsupported format")
}
func keyFromSlice(parts []string) (ipsecKey, error) {
if len(parts) != 5 {
return ipsecKey{}, fmt.Errorf("IPsec key invalid [expected parts: 5, actual parts: %d]", len(parts))
}
parts[1] = strings.TrimSuffix(parts[1], "+")
spi, err := strconv.Atoi(parts[1])
if err != nil {
return ipsecKey{}, fmt.Errorf("invalid IPsec key SPI: %s", parts[1])
}
size, err := strconv.Atoi(parts[4])
if err != nil {
return ipsecKey{}, fmt.Errorf("invalid IPsec key size: %s", parts[4])
}
key := ipsecKey{
spi: spi,
algo: parts[2],View on GitHub (pinned to ac7b90affa)
Solutions
- Print the secret value and compare to the expected format '<spi> rfc4106(gcm(aes)) <128/256-bit hex key>'
- Strip stray whitespace/newlines and rewrite the key in the canonical format
- Use matching CLI/agent versions so parser regexes cover the key format; otherwise recreate via create-key/rotate-key
Example fix
// before: malformed key "rfc4106(gcm(aes)) abc123" // after "3 rfc4106(gcm(aes)) 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
Defensive patterns
Strategy: validation
Validate before calling
const re = /^\d+\s+rfc4106\(gcm\(aes\)\)\s+[0-9a-fA-F]+$/m
if (!re.test(keyStr.trim())) throw new Error('key string not in supported format') Type guard
function isWellFormedKey(s) { return typeof s === 'string' && /^\d+\s+rfc4106\(gcm\(aes\)\)\s+[0-9a-f]+$/i.test(s.trim()) } Try / catch
try { await IPsecRotateKey(ctx) } catch (err) { if (/unsupported format/.test(err.message)) { /* rewrite secret keys value canonically or recreate */ } throw err } Prevention
- Never hand-edit key strings; generate with cilium-cli
- Trim whitespace/newlines when copying keys between tools
- Match cilium-cli version to the cluster version that wrote the key
When it happens
Trigger: IPsecRotateKey reads secret.Data["keys"] and ipsecKeyFromString fails to match any parser — e.g. wrong number of fields, missing rfc4106(gcm(aes)) marker, whitespace/newline corruption, or a future/newer format.
Common situations: Secrets edited by hand with dropped fields; keys written by newer cilium versions with formats the CLI's parser set doesn't know; trailing newlines or CRLF from manual edits.
Related errors
- IPsec key invalid [expected parts: 5, actual parts: %d]
- invalid IPsec key SPI: %s
- invalid IPsec key size: %s
- IPsec key invalid [expected parts: 6, actual parts: %d]
- invalid cipher IPsec key SPI: %s
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/f39bf61161aa72e9.
Report an issue: GitHub.