hashicorp/packer · error
marshal artifact identity: %w
Error message
marshal artifact identity: %w
What it means
When the artifact has no files, deriveSubjects falls back to digesting a canonical JSON identity record (builderId, id, optional registry state). If json.Marshal of that identity map fails, the error is wrapped as `marshal artifact identity: %w`. In practice this is rare because map[string]interface{} with JSON-normalized values is almost always marshalable.
Source
Thrown at internal/provenance/subject.go:66
subjects = append(subjects, Subject{
Name: filepath.Base(file),
Digest: DigestSet{
"sha256": digest,
},
})
}
return subjects, nil
}
identity, err := deriveIdentityRecord(artifact)
if err != nil {
return nil, err
}
canonicalIdentity, err := json.Marshal(identity)
if err != nil {
return nil, fmt.Errorf("marshal artifact identity: %w", err)
}
digest := sha256.Sum256(canonicalIdentity)
return []Subject{{
Name: fmt.Sprintf("%s:%s", artifact.BuilderId(), artifact.Id()),
Digest: DigestSet{
"sha256": hex.EncodeToString(digest[:]),
},
}}, nil
}
func deriveIdentityRecord(artifact packersdk.Artifact) (map[string]interface{}, error) {
if artifact == nil {
return nil, fmt.Errorf("artifact is nil")
}
record := map[string]interface{}{View on GitHub (pinned to eb36e3c3e4)
Solutions
- Inspect the wrapped cause from %w to see which value failed to marshal
- Check what the builder stores under registryimage.ArtifactStateURI and make it JSON-serializable
- Ensure custom Artifact.State() returns plain JSON-safe types (maps, slices, strings, numbers)
- Re-run with a stock builder to confirm the issue is plugin-specific
Example fix
// before
record["state"] = someRuntimeValue // may be unmarshalable
// after
enc, err := json.Marshal(someRuntimeValue)
if err != nil {
return record, nil // omit unusable state instead of failing identity digest
}
var safe interface{}
_ = json.Unmarshal(enc, &safe)
record["state"] = safe Defensive patterns
Strategy: validation
Validate before calling
state := artifact.State(registryimage.ArtifactStateURI)
if state != nil {
if _, err := json.Marshal(state); err != nil {
log.Warn("artifact state not JSON-serializable; identity digest will use builder info only")
}
} Type guard
func jsonSafe(v interface{}) bool { _, err := json.Marshal(v); return err == nil } Try / catch
subjects, err := provenance.DeriveSubjects(artifact)
if err != nil {
if strings.Contains(err.Error(), "marshal artifact identity") { return fmt.Errorf("artifact state unusable: %w", err) }
return err
} Prevention
- Store only JSON-safe values under ArtifactStateURI
- Round-trip plugin state through json.Marshal/Unmarshal before attaching
- Keep packer-plugin-sdk updated together with syft/provenance code
When it happens
Trigger: The artifact's state at registryimage.ArtifactStateURI contains values json.Marshal cannot encode (e.g. channels, funcs, cyclic structures) that survived normalizeJSONValue, or normalizeJSONValue silently returned the record without normalization on its own error path.
Common situations: A custom builder or plugin injects a non-JSON-serializable ArtifactStateURI value; custom Artifact implementations returning exotic State() payloads; unexpected changes in packer-plugin-sdk state types after an SDK upgrade.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- marshal attestation payload: %w
- marshal signed envelope: %w
- marshal Sigstore bundle: %w
- artifact is nil
- malformed packer SBOM output from file %q: %s
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/d74238384693c765.
Report an issue: GitHub.