hashicorp/packer · error
attestation builder id %q does not match expected %q
Error message
attestation builder id %q does not match expected %q
What it means
When the policy sets BuilderID, verifyPolicy compares it to predicate.runDetails.builder.id of the SLSA v1 provenance. This error means the attestation was produced by a different builder than the policy trusts.
Source
Thrown at internal/attestation/verify.go:256
}
if policy.BuilderID != "" || policy.SourceURI != "" {
if statement.PredicateType != internalprovenance.SLSAProvenanceV1PredicateType {
return nil, fmt.Errorf("builder and source policy checks require predicate type %q, got %q", internalprovenance.SLSAProvenanceV1PredicateType, statement.PredicateType)
}
var typedStatement struct {
Type string `json:"_type"`
Subject []internalprovenance.Subject `json:"subject"`
PredicateType string `json:"predicateType"`
Predicate internalprovenance.SLSAProvenancePredicate `json:"predicate"`
}
if err := json.Unmarshal(payload, &typedStatement); err != nil {
return nil, fmt.Errorf("decode SLSA predicate for policy verification: %w", err)
}
if policy.BuilderID != "" && typedStatement.Predicate.RunDetails.Builder.ID != policy.BuilderID {
return nil, fmt.Errorf("attestation builder id %q does not match expected %q", typedStatement.Predicate.RunDetails.Builder.ID, policy.BuilderID)
}
if policy.SourceURI != "" {
matched := false
for _, dependency := range typedStatement.Predicate.BuildDefinition.ResolvedDependencies {
if dependency.URI == policy.SourceURI {
matched = true
break
}
}
if !matched {
return nil, fmt.Errorf("attestation does not contain expected source URI %q", policy.SourceURI)
}
}
}
return &statement, nil
}View on GitHub (pinned to eb36e3c3e4)
Solutions
- Check the error's two IDs: the attestation's actual builder.id versus policy expectation; fix whichever is wrong.
- Update policy.BuilderID to the exact builder ID your CI emits (match URI format exactly).
- Re-run the build on the builder specified in the policy and use its attestation.
- If multiple builders are trusted, verify each with its own policy rather than a single BuilderID.
Example fix
// before policy.BuilderID = "https://github.com/actions/runner" // attestation says "https://circleci.com" // after policy.BuilderID = "https://circleci.com" // or rebuild on GitHub Actions
Defensive patterns
Strategy: validation
Validate before calling
var s struct {
Predicate struct {
RunDetails struct {
Builder struct{ ID string `json:"id"` } `json:"builder"`
} `json:"runDetails"`
} `json:"predicate"`
}
_ = json.Unmarshal(payload, &s)
if policy.BuilderID != "" && s.Predicate.RunDetails.Builder.ID != policy.BuilderID {
return fmt.Errorf("builder %q not trusted", s.Predicate.RunDetails.Builder.ID)
} Try / catch
_, err := VerifyAttestationFile(path, policy)
if err != nil && strings.Contains(err.Error(), "builder id") {
// error message shows actual vs expected; update policy or rebuild on trusted builder
} Prevention
- Copy BuilderID byte-for-byte from a known-good attestation's runDetails.builder.id
- Keep a trust list of builder IDs and match exactly
- Re-run builds on the pinned builder when provenance comes from elsewhere
When it happens
Trigger: VerifyAttestationFile with policy.BuilderID set (e.g. "https://github.com/actions/runner") on an attestation whose runDetails.builder.id differs (empty or another CI system's ID).
Common situations: Rebuilt artifacts produced by a different CI pipeline than the one in policy; builder ID configured with wrong URI format (missing scheme or trailing difference); attestations from a fork's runner while policy pins the upstream builder.
Related errors
- builder and source policy checks require predicate type %q,
- decode SLSA predicate for policy verification: %w
- attestation does not contain expected source URI %q
- signing_mode %q does not support Sigstore bundle emission
- decode envelope payload: %w
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/376cc86cf459d8ba.
Report an issue: GitHub.