golang/go · error

preprocessed profile contains duplicate edge %+v

Error message

preprocessed profile contains duplicate edge %+v

What it means

Thrown when the preprocessed PGO profile contains the same NamedCallEdge (caller + callee + call-site offset triple) more than once. The deserializer detects this via a map lookup before inserting and rejects duplicates to prevent double-counting weights. The %+v formats the full edge struct for identification.

Source

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

		co, err := strconv.Atoi(split[0])
		if err != nil {
			return nil, fmt.Errorf("preprocessed profile error processing call line: %w", err)
		}

		edge := NamedCallEdge{
			CallerName:     callerName,
			CalleeName:     calleeName,
			CallSiteOffset: co,
		}

		weight, err := strconv.ParseInt(split[1], 10, 64)
		if err != nil {
			return nil, fmt.Errorf("preprocessed profile error processing call weight: %w", err)
		}

		if _, ok := d.NamedEdgeMap.Weight[edge]; ok {
			return nil, fmt.Errorf("preprocessed profile contains duplicate edge %+v", edge)
		}

		d.NamedEdgeMap.ByWeight = append(d.NamedEdgeMap.ByWeight, edge) // N.B. serialization is ordered.
		d.NamedEdgeMap.Weight[edge] += weight
		d.TotalWeight += weight
	}

	return d, nil

}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Regenerate the profile from a single profiling run to avoid duplicate edges from manual concatenation.
  2. If merging profiles, deduplicate edges and sum their weights before serialization.
  3. Inspect the profile for the duplicated edge (identified by the %+v output) and remove the redundant entry.
  4. Report a bug if the Go toolchain's own preprocessing produced the duplicate.

Example fix

// Data fix: if two entries share the same edge, merge them:
// Before:
//   caller
callee
42 100
//   caller
callee
42 200
// After (summed):
//   caller
callee
42 300
Defensive patterns

Strategy: validation

Validate before calling

// Pre-deduplicate edges before serialization:
func deduplicateEdges(edges []NamedCallEdge, weights []int64) ([]NamedCallEdge, []int64) {
    merged := make(map[NamedCallEdge]int64)
    for i, e := range edges {
        merged[e] += weights[i]
    }
    uniq := make([]NamedCallEdge, 0, len(merged))
    uniqW := make([]int64, 0, len(merged))
    for e, w := range merged {
        uniq = append(uniq, e)
        uniqW = append(uniqW, w)
    }
    return uniq, uniqW
}

Prevention

When it happens

Trigger: A NamedCallEdge with identical CallerName, CalleeName, and CallSiteOffset appears in two separate edge entries in the profile. The check `d.NamedEdgeMap.Weight[edge]` returns ok=true on the second occurrence.

Common situations: A bug in the profile serialization or preprocessing step that emits the same edge twice instead of summing weights. Can also happen if two different source-level call sites resolve to the same offset due to inlining or if the profile was concatenated from multiple runs without deduplication.

Related errors


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