pulumi/pulumi · error
encryptedlog: invalid magic bytes
Error message
encryptedlog: invalid magic bytes
What it means
After successfully reading the first 4 bytes, NewReader compares them against the encryptedlog Magic constant. Mismatched magic means the stream is not a Pulumi encrypted log at all — most commonly a plaintext log or a different binary format — so parsing is rejected immediately.
Source
Thrown at pkg/engine/encryptedlog/reader.go:48
// Reader reads and decrypts PLOG encrypted log files,
// returning the original plaintext log data. It tolerates missing
// end sentinels for crash resilience — all completed chunks are readable.
type Reader struct {
cd *chunkDecrypter
}
// NewReader creates an Reader that decrypts log data from r.
// The session key stored in the file header is decrypted with dec.
func NewReader(
ctx context.Context, r io.Reader, dec config.Decrypter,
) (*Reader, error) {
var magic [4]byte
if _, err := io.ReadFull(r, magic[:]); err != nil {
return nil, fmt.Errorf("encryptedlog: reading magic: %w", err)
}
if string(magic[:]) != Magic {
return nil, errors.New("encryptedlog: invalid magic bytes")
}
var versionBuf [1]byte
if _, err := io.ReadFull(r, versionBuf[:]); err != nil {
return nil, fmt.Errorf("encryptedlog: reading version: %w", err)
}
version := versionBuf[0]
if version != Version {
return nil, fmt.Errorf("encryptedlog: unsupported version %d", version)
}
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)View on GitHub (pinned to 793f7b2e16)
Solutions
- Confirm the log is actually encrypted (check `pulumi logs`/backend settings or the file's first bytes against the Magic constant).
- If the log is plaintext, read it directly instead of through encryptedlog.NewReader.
- If the format/version differs, regenerate or re-export the log from the backend that produced it rather than hand-editing bytes.
Example fix
// before
r, err := encryptedlog.NewReader(ctx, plaintextFile, dec) // invalid magic bytes
// after
buf := make([]byte, 4)
io.ReadFull(plaintextFile, buf)
if string(buf) != encryptedlog.Magic {
return errors.New("not an encrypted log; read as plain text")
}
plaintextFile.Seek(0, io.Start)
r, err := encryptedlog.NewReader(ctx, plaintextFile, dec) Defensive patterns
Strategy: validation
Validate before calling
// Go: sniff magic bytes before decoding
br := bufio.NewReader(r)
magic, err := br.Peek(len(encryptedlog.Magic))
if err != nil || string(magic) != encryptedlog.Magic {
return errors.New("stream is not an encrypted Pulumi log")
} Type guard
// Go
func isEncryptedLog(r io.Reader) (bool, io.Reader) {
br := bufio.NewReader(r)
magic, err := br.Peek(4)
return err == nil && string(magic) == encryptedlog.Magic, br
} Try / catch
// Go
if _, err := encryptedlog.NewReader(ctx, br, dec); err != nil {
if strings.Contains(err.Error(), "invalid magic bytes") {
return errors.New("not an encrypted log; treat as plain text")
}
return err
} Prevention
- Only feed logs produced with encryption enabled into encryptedlog.NewReader
- Detect format by peeking magic bytes before choosing a reader path
- Avoid hand-editing or concatenating encrypted log files
When it happens
Trigger: Calling encryptedlog.NewReader on a log that was never encrypted (plain `pulumi up` output), a log encrypted with a different/older format, or a file whose first bytes were altered/prepended.
Common situations: Pointing the encrypted-log reader at ordinary log files; backend misconfig where encryption was disabled after logs were assumed encrypted; concatenating plaintext and encrypted logs.
Related errors
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/b170a0eaf64a7a9f.
Report an issue: GitHub.