golang/go · error

preprocessed profile entry missing callee

Error message

preprocessed profile entry missing callee

What it means

A serialized PGO profile is a sequence of caller/callee/weight line triplets. After reading a caller line, the next Scan returned false with no error — meaning the file ended before the callee line was present. The record is therefore incomplete.

Solutions

  1. Regenerate the profile cleanly with Profile.WriteTo.
  2. Ensure the writing process completes and the file is flushed/closed.
  3. Validate with IsSerialized and check the file size before parsing.
Defensive patterns

Strategy: validation

Validate before calling

// Sanity-check that the profile has a multiple-of-three record body.
// lines := strings.Split(strings.TrimSpace(string(data)), "\n")
// if (len(lines)-1)%3 != 0 { return errors.New("profile record count not a multiple of 3") }

Try / catch

// prof, err := pgo.FromSerialized(r)
// if err != nil {
//     if err.Error() == "preprocessed profile entry missing callee" ||
//        err.Error() == "preprocessed profile entry missing weight" {
//         // truncated record; regenerate the profile
//     }
//     return err
// }

Prevention

When it happens

Trigger: An odd number of remaining lines (a caller with no callee) due to the file being truncated mid-record.

Common situations: A profile file that was cut off while being written (disk full, process killed), leaving a dangling caller line.

Related errors


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

Appendix: source

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

		if err := scanner.Err(); err != nil {
			return nil, fmt.Errorf("error reading preprocessed profile: %w", err)
		}
		return nil, fmt.Errorf("preprocessed profile missing header")
	}
	if gotHdr := scanner.Text() + "\n"; gotHdr != serializationHeader {
		return nil, fmt.Errorf("preprocessed profile malformed header; got %q want %q", gotHdr, serializationHeader)
	}

	for scanner.Scan() {
		readStr := scanner.Text()

		callerName := readStr

		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 entry missing callee")
		}
		calleeName := scanner.Text()

		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 entry missing weight")
		}
		readStr = scanner.Text()

		split := strings.Split(readStr, " ")

		if len(split) != 2 {
			return nil, fmt.Errorf("preprocessed profile entry got %v want 2 fields", split)
		}

		co, err := strconv.Atoi(split[0])

View on GitHub (pinned to b6b368adc5)