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

  1. Check the error's two IDs: the attestation's actual builder.id versus policy expectation; fix whichever is wrong.
  2. Update policy.BuilderID to the exact builder ID your CI emits (match URI format exactly).
  3. Re-run the build on the builder specified in the policy and use its attestation.
  4. 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

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


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/376cc86cf459d8ba. Report an issue: GitHub.