{"record":{"id":"32a8e9df24db39a1","repo":"cli/cli","slug":"failed-to-write-attestation-v","errorCode":null,"errorMessage":"failed to write attestation: %v","messagePattern":"failed to write attestation: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/cmd/attestation/download/download.go","lineNumber":164,"sourceCode":"\t\t\tfmt.Fprintf(opts.Logger.IO.Out, \"No attestations found for %s\\n\", opts.ArtifactPath)\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"failed to fetch attestations: %v\", err)\n\t}\n\n\t// Apply predicate type filter to returned attestations\n\tif opts.PredicateType != \"\" {\n\t\tfilteredAttestations, err := api.FilterAttestations(opts.PredicateType, attestations)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to filter attestations: %v\", err)\n\t\t}\n\n\t\tattestations = filteredAttestations\n\t}\n\n\tmetadataFilePath, err := opts.Store.createMetadataFile(artifact.DigestWithAlg(), attestations)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to write attestation: %v\", err)\n\t}\n\tfmt.Fprintf(opts.Logger.IO.Out, \"Wrote attestations to file %s.\\nAny previous content has been overwritten\\n\\n\", metadataFilePath)\n\n\tfmt.Fprint(opts.Logger.IO.Out,\n\t\topts.Logger.ColorScheme.Greenf(\n\t\t\t\"The trusted metadata is now available at %s\\n\", metadataFilePath,\n\t\t),\n\t)\n\n\treturn nil\n}\n","sourceCodeStart":146,"sourceCodeEnd":176,"githubUrl":"https://github.com/cli/cli/blob/0eeec0b92edbe70199f9768522f831d3534f41ad/pkg/cmd/attestation/download/download.go#L146-L176","documentation":"Thrown by `gh attestation download` when the local metadata store (LiveStore.createMetadataFile) fails to write the .jsonl bundle file for the downloaded attestations. This is a local filesystem failure after a successful API fetch: file creation, JSON marshalling, writing, or closing failed (the wrapped error says which).","triggerScenarios":"os.Create on the output path fails (unwritable directory, permission denied, invalid path on Windows due to colons in the digest), json.Marshal of a bundle fails, f.Write fails (disk full), or f.Close fails.","commonSituations":"Using -O/--output-dir pointing to a read-only or nonexistent directory, running without write permission in the current directory, or a digest-derived filename containing characters the filesystem rejects.","solutions":["Check the wrapped message to see which step failed (create/marshall/write/close)","Ensure the output directory exists and is writable: mkdir -p <dir> && touch <dir>/test","If -O was passed, verify the path; otherwise ensure the current directory is writable","Free disk space or fix permissions and rerun"],"exampleFix":"# before\ngh attestation download ./artifact.bin -O /readonly/dir\n# after\nmkdir -p ./attestations && gh attestation download ./artifact.bin -O ./attestations","handlingStrategy":"validation","validationCode":"dir := \".\"\nif opts.OutputPath != \"\" { dir = opts.OutputPath }\ninfo, err := os.Stat(dir)\nif err != nil || !info.IsDir() || info.Mode().Perm()&0200 == 0 {\n\treturn fmt.Errorf(\"output dir %q missing or not writable\", dir)\n}","typeGuard":null,"tryCatchPattern":"path, err := store.createMetadataFile(digest, attestations)\nif err != nil {\n\treturn fmt.Errorf(\"persist attestations for %s: %w\", digest, err)\n}","preventionTips":["Pre-create the output directory (mkdir -p) before download","Check writable permissions and free disk space in CI preflight","Use errors.Is(err, ErrAttestationFileCreation) to distinguish local I/O failures from API failures"],"tags":["filesystem","attestation","permissions","io"],"backgroundTag":null,"analyzedSha":"0eeec0b92edbe70199f9768522f831d3534f41ad","analyzedAt":"2026-08-15T12:31:05.478Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}