golang/go · error

profile missing Function.start_line data (Go version of prof

Error message

profile missing Function.start_line data (Go version of profiled application too old? Go 1.20+ automatically adds this to profiles)

What it means

Thrown when the pprof profile's Function entries lack start_line information (seenStartLine is false after iterating all graph nodes). The PGO inliner needs relative line numbers derived from Function.start_line to compute call-site offsets. Go 1.20+ automatically includes start_line in emitted profiles; older versions do not, making them incompatible with PGO. The error message itself suggests this cause.

Source

Thrown at src/cmd/internal/pgo/pprof.go:106

		// Create the key to the nodeMapKey.
		namedEdge := NamedCallEdge{
			CallerName:     canonicalName,
			CallSiteOffset: n.Info.Lineno - n.Info.StartLine,
		}

		for _, e := range n.Out {
			totalWeight += e.WeightValue()
			namedEdge.CalleeName = e.Dest.Info.Name
			// Create new entry or increment existing entry.
			weight[namedEdge] += e.WeightValue()
		}
	}

	if !seenStartLine {
		// TODO(prattmic): If Function.start_line is missing we could
		// fall back to using absolute line numbers, which is better
		// than nothing.
		return NamedEdgeMap{}, 0, fmt.Errorf("profile missing Function.start_line data (Go version of profiled application too old? Go 1.20+ automatically adds this to profiles)")
	}
	return postProcessNamedEdgeMap(weight, totalWeight)
}

func sortByWeight(edges []NamedCallEdge, weight map[NamedCallEdge]int64) {
	sort.Slice(edges, func(i, j int) bool {
		ei, ej := edges[i], edges[j]
		if wi, wj := weight[ei], weight[ej]; wi != wj {
			return wi > wj // want larger weight first
		}
		// same weight, order by name/line number
		if ei.CallerName != ej.CallerName {
			return ei.CallerName < ej.CallerName
		}
		if ei.CalleeName != ej.CalleeName {
			return ei.CalleeName < ej.CalleeName
		}
		return ei.CallSiteOffset < ej.CallSiteOffset

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Rebuild the profiled application with Go 1.20 or later, then re-collect the CPU profile.
  2. Ensure the binary was not stripped of debug info (-ldflags='-s -w' removes symbols; avoid this for profiling builds).
  3. Verify the Go version used to build the profiled binary: `go version <binary>`.
  4. Confirm the pprof profile has Function.start_line by inspecting it with `go tool pprof -proto <file> | grep start_line`.

Example fix

// Rebuild with Go 1.20+:
// go1.21 build -o myapp .
// ./myapp  # run representative workload
// (profile collected with runtime/pprof or SIGUSR1)
// go build -pgo=cpu.prof
Defensive patterns

Strategy: validation

Validate before calling

// Check Go version of the binary that produced the profile:
func checkGoVersionForPGO(binaryPath string) error {
    out, err := exec.Command("go", "version", binaryPath).CombinedOutput()
    if err != nil { return err }
    s := string(out)
    // Must be go1.20+
    if !strings.Contains(s, "go1.2") && !strings.Contains(s, "go1.3") {
        return fmt.Errorf("binary built with %s; PGO requires Go 1.20+ for start_line", s)
    }
    return nil
}

Prevention

When it happens

Trigger: After building the profile graph and iterating all nodes' Out edges, no Function.Info has a non-zero start_line, so seenStartLine remains false. This happens when the profiled binary was built with Go < 1.20, which doesn't populate Function.start_line in the pprof metadata.

Common situations: Profiling an application built with Go 1.19 or earlier, then attempting to use that profile for PGO (which requires Go 1.21+). Also possible with profiles from non-Go applications or stripped binaries where symbol/debug info is incomplete.

Related errors


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