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

  1. Confirm the log is actually encrypted (check `pulumi logs`/backend settings or the file's first bytes against the Magic constant).
  2. If the log is plaintext, read it directly instead of through encryptedlog.NewReader.
  3. 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

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.