{"record":{"id":"13042bdd21a63451","repo":"hashicorp/packer","slug":"artifact-is-nil","errorCode":null,"errorMessage":"artifact is nil","messagePattern":"artifact is nil","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/provenance/subject.go","lineNumber":36,"sourceCode":"\ntype DigestSet map[string]string\n\ntype Subject struct {\n\tName   string    `json:\"name\"`\n\tDigest DigestSet `json:\"digest\"`\n}\n\nfunc DeriveSubjects(artifact packersdk.Artifact) ([]Subject, error) {\n\treturn deriveSubjects(artifact)\n}\n\nfunc DeriveIdentityRecord(artifact packersdk.Artifact) (map[string]interface{}, error) {\n\treturn deriveIdentityRecord(artifact)\n}\n\nfunc deriveSubjects(artifact packersdk.Artifact) ([]Subject, error) {\n\tif artifact == nil {\n\t\treturn nil, fmt.Errorf(\"artifact is nil\")\n\t}\n\n\tfiles := artifact.Files()\n\tif len(files) > 0 {\n\t\tsubjects := make([]Subject, 0, len(files))\n\t\tfor _, file := range files {\n\t\t\tdigest, err := sha256File(file)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"hash %q: %w\", file, err)\n\t\t\t}\n\n\t\t\tsubjects = append(subjects, Subject{\n\t\t\t\tName: filepath.Base(file),\n\t\t\t\tDigest: DigestSet{\n\t\t\t\t\t\"sha256\": digest,\n\t\t\t\t},\n\t\t\t})\n\t\t}","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/provenance/subject.go#L18-L54","documentation":"deriveSubjects in internal/provenance/subject.go refuses to operate on a nil packersdk.Artifact. Subject derivation (SHA-256 digests of artifact files, or a digest over the builder identity) requires a concrete artifact, so a nil input is rejected up front with a plain error. It is a defensive guard: callers passing a nil artifact have lost the build output somewhere upstream.","triggerScenarios":"Calling DeriveSubjects(nil) or DeriveIdentityRecord(nil), or passing an artifact variable that a builder/plugin returned as nil (e.g. a build with no artifact) into those functions.","commonSituations":"A builder produced no artifact (failed or imageless build) and post-processing/provenance code still runs; iterating over multiple artifacts where one entry is nil; wiring a post-processor where artifact retrieval was skipped on error.","solutions":["Check artifact != nil before calling DeriveSubjects / DeriveIdentityRecord","Verify the upstream builder actually produced an artifact (check build errors and artifact list length)","In loops over artifacts, skip nil entries explicitly","Wrap the call in error handling and degrade gracefully (skip provenance for that artifact)"],"exampleFix":"// before\nsubjects, err := provenance.DeriveSubjects(artifact)\n// after\nif artifact == nil {\n    return nil // no artifact produced; skip provenance\n}\nsubjects, err := provenance.DeriveSubjects(artifact)","handlingStrategy":"validation","validationCode":"if artifact == nil {\n    return nil, fmt.Errorf(\"no artifact produced by build; skipping provenance\")\n}\n_ = artifact // safe to pass","typeGuard":"func isNilArtifact(a packersdk.Artifact) bool { return a == null || reflect.ValueOf(a).IsNil() }","tryCatchPattern":"subjects, err := provenance.DeriveSubjects(artifact)\nif err != nil {\n    if err.Error() == \"artifact is nil\" { log.Warn(\"no artifact; skipping subjects\"); return nil }\n    return err\n}","preventionTips":["Nil-check artifacts immediately after build completion","Skip provenance steps when a build yields zero artifacts","Treat nil artifact as 'nothing to attest', not a crash"],"tags":["go","nil-pointer","artifact","provenance"],"backgroundTag":"nil-artifact","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}