golang/go · error

error reading profile header

Error message

error reading profile header: %w

What it means

IsSerialized peeks at the first len(serializationHeader) bytes of a buffered reader to decide whether the stream is a serialized PGO profile. EOF is treated as 'empty file, not serialized' (not an error); any other peek failure is wrapped and returned. This guards FromSerialized against consuming the wrong kind of stream.

Solutions

  1. Verify the reader is healthy and positioned at the start of the profile.
  2. Buffer the profile into a bytes.Reader from a verified file before calling IsSerialized.
  3. Retry once if the source is transiently failing.

Example fix

// before: reader may fail mid-peek
ok, err := pgo.IsSerialized(bufReader)

// after: materialize then peek a stable reader
data, err := os.ReadFile(profilePath)
if err != nil { return err }
ok, err := pgo.IsSerialized(bufio.NewReader(bytes.NewReader(data)))
Defensive patterns

Strategy: validation

Validate before calling

// Materialize the profile so Peek operates on a stable reader.
// data, err := os.ReadFile(path)
// if err != nil { return err }
// br := bufio.NewReader(bytes.NewReader(data))
// ok, err := pgo.IsSerialized(br)
// if err != nil { return fmt.Errorf("profile unreadable: %w", err) }

Try / catch

// ok, err := pgo.IsSerialized(br)
// if err != nil {
//     // header peek failed: bad reader or truncated; retry from a buffered copy
//     return err
// }

Prevention

When it happens

Trigger: r.Peek fails with an error other than io.EOF — e.g. an underlying reader that errors mid-stream, a network-backed reader that drops, or a corrupted file descriptor.

Common situations: Reading a profile over an unstable source (pipe, socket, network), a truncated file, or a reader that has already been closed.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/a5d2a66f400783ca. Report an issue: GitHub.

Appendix: source

Thrown at src/cmd/internal/pgo/deserialize.go:25

import (
	"bufio"
	"fmt"
	"io"
	"strconv"
	"strings"
)

// IsSerialized returns true if r is a serialized Profile.
//
// IsSerialized only peeks at r, so seeking back after calling is not
// necessary.
func IsSerialized(r *bufio.Reader) (bool, error) {
	hdr, err := r.Peek(len(serializationHeader))
	if err == io.EOF {
		// Empty file.
		return false, nil
	} else if err != nil {
		return false, fmt.Errorf("error reading profile header: %w", err)
	}

	return string(hdr) == serializationHeader, nil
}

// FromSerialized parses a profile from serialization output of Profile.WriteTo.
func FromSerialized(r io.Reader) (*Profile, error) {
	d := emptyProfile()

	scanner := bufio.NewScanner(r)
	scanner.Split(bufio.ScanLines)

	if !scanner.Scan() {
		if err := scanner.Err(); err != nil {
			return nil, fmt.Errorf("error reading preprocessed profile: %w", err)
		}
		return nil, fmt.Errorf("preprocessed profile missing header")
	}

View on GitHub (pinned to b6b368adc5)