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

  1. Inspect the wrapped cause from %w to see which value failed to marshal
  2. Check what the builder stores under registryimage.ArtifactStateURI and make it JSON-serializable
  3. Ensure custom Artifact.State() returns plain JSON-safe types (maps, slices, strings, numbers)
  4. 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

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


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