pulumi/pulumi · error

encryptedlog: invalid session key size %d

Error message

encryptedlog: invalid session key size %d

What it means

The session key decrypted from the header does not have the expected keySize length (32 bytes for AES-256). Decryption succeeded, but the plaintext key is the wrong size, so the reader rejects it instead of constructing a cipher with an invalid key.

Source

Thrown at pkg/engine/encryptedlog/reader.go:77

	var keyLenBuf [2]byte
	if _, err := io.ReadFull(r, keyLenBuf[:]); err != nil {
		return nil, fmt.Errorf("encryptedlog: reading key length: %w", err)
	}
	keyLen := binary.BigEndian.Uint16(keyLenBuf[:])

	encryptedKeyBytes := make([]byte, keyLen)
	if _, err := io.ReadFull(r, encryptedKeyBytes); err != nil {
		return nil, fmt.Errorf("encryptedlog: reading encrypted key: %w", err)
	}

	decryptedKey, err := dec.DecryptValue(ctx, string(encryptedKeyBytes))
	if err != nil {
		return nil, fmt.Errorf("encryptedlog: decrypting session key: %w", err)
	}
	sessionKey := []byte(decryptedKey)
	if len(sessionKey) != keySize {
		return nil, fmt.Errorf("encryptedlog: invalid session key size %d", len(sessionKey))
	}

	// Set up AES-256-GCM from the session key.
	block, err := aes.NewCipher(sessionKey)
	if err != nil {
		return nil, fmt.Errorf("encryptedlog: creating cipher: %w", err)
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, fmt.Errorf("encryptedlog: creating GCM: %w", err)
	}

	return &Reader{cd: &chunkDecrypter{r: r, aesgcm: aesgcm}}, nil
}

// Read reads decrypted, decompressed log data.
func (elr *Reader) Read(p []byte) (int, error) {
	return elr.cd.Read(p)

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Confirm the encrypted log and the decrypter belong to the same stack/deployment (same secret key material).
  2. Check whether your secrets provider returns decoded raw bytes; unwrap/base64-decode if it returns an envelope.
  3. Re-export the log so it is written with the current secrets provider and key.

Example fix

// before: decrypting ciphertext from a different stack
dec := stackDecrypter(otherStack)
rdr, err := encryptedlog.NewReader(ctx, f, dec) // invalid session key size
// after: use the decrypter for the stack that produced the log
dec := stackDecrypter(logSourceStack)
rdr, err := encryptedlog.NewReader(ctx, f, dec)
Defensive patterns

Strategy: validation

Validate before calling

plain, err := dec.DecryptValue(ctx, ciphertextB64)
if err == nil && len(plain) != 32 {
	return fmt.Errorf("decrypter returned %d bytes, expected a 32-byte AES-256 key; wrong stack/provider?", len(plain))
}

Try / catch

rdr, err := encryptedlog.NewReader(ctx, r, dec)
if err != nil && strings.Contains(err.Error(), "invalid session key size") {
	return errors.New("decrypter does not correspond to this log's secrets provider; use the originating stack's decrypter")
}

Prevention

When it happens

Trigger: Calling NewReader with a Decrypter that returns something other than the raw 32-byte session key — e.g. decrypting ciphertext that was not the session key (wrong stack's ciphertext), or a decrypter that returns a wrapper/JSON envelope rather than raw bytes.

Common situations: Pointing a decrypter at a ciphertext from a different stack or file; secrets providers that base64-wrap values; mixing log files and secret configurations from different deployments.

Related errors


AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31). Data as JSON: /api/errors/1e5e8adca71118d9. Report an issue: GitHub.