cilium/cilium · error

invalid cipher IPsec key SPI: %s

Error message

invalid cipher IPsec key SPI: %s

What it means

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.

Source

Thrown at cilium-cli/encrypt/ipsec_rotate_key.go:118

		return ipsecKey{}, fmt.Errorf("invalid IPsec key size: %s", parts[4])
	}
	key := ipsecKey{
		spi:  spi,
		algo: parts[2],
		key:  parts[3],
		size: size,
	}
	return key, nil
}

func cipherKeyFromSlice(parts []string) (ipsecKey, error) {
	if len(parts) != 6 {
		return ipsecKey{}, fmt.Errorf("IPsec key invalid [expected parts: 6, 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 cipher IPsec key SPI: %s", parts[1])
	}
	key := ipsecKey{
		spi:        spi,
		algo:       parts[2],
		key:        parts[3],
		cipherMode: parts[4],
		cipherKey:  parts[5],
	}
	return key, nil
}

const maxIPsecSPI = 16

func (k ipsecKey) rotate() (ipsecKey, error) {
	key, err := generateRandomHex(len(k.key))
	if err != nil {
		return ipsecKey{}, fmt.Errorf("failed to generate authentication key: %w", err)
	}

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Ensure field 2 is a decimal SPI, optionally ending in '+' (e.g. '15+'); fix the token or field order.
  2. Validate the full 6-field layout: spi, auth-algo, auth-key, cipher-mode, cipher-key, size.
  3. Regenerate the key entry with Cilium's cipher key format and update the secret before rotating.

Example fix

// before
"hmac-sha256 abcdef rfc4106(gcm(aes)) 0123456789abcdef 128" // SPI missing
// after
"15+ hmac-sha256 abcdef rfc4106(gcm(aes)) 0123456789abcdef 128"
Defensive patterns

Strategy: validation

Validate before calling

parts := strings.Fields(keyLine)
if len(parts) != 6 {
    return fmt.Errorf("expected 6 fields, got %d", len(parts))
}
if _, err := strconv.Atoi(strings.TrimSuffix(parts[1], "+")); err != nil {
    return fmt.Errorf("field 2 must be numeric SPI, got %q", parts[1])
}

Type guard

func validCipherKeyLine(line string) bool {
    parts := strings.Fields(line)
    if len(parts) != 6 { return false }
    _, err := strconv.Atoi(strings.TrimSuffix(parts[1], "+"))
    return err == nil
}

Try / catch

key, err := cipherKeyFromSlice(parts)
if err != nil {
    if strings.Contains(err.Error(), "invalid cipher IPsec key SPI") {
        // fix SPI token/field order and retry
    }
    return err
}

Prevention

When it happens

Trigger: 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 '+'.

Common situations: 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.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/af466bd831a0100d. Report an issue: GitHub.