{"record":{"id":"99a980f2db5cf68c","repo":"GoogleContainerTools/skaffold","slug":"failed-to-copy-rendered-manifests-to-gcs-w","errorCode":null,"errorMessage":"failed to copy rendered manifests to GCS: %w","messagePattern":"failed to copy rendered manifests to GCS: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/kubernetes/manifest/util.go","lineNumber":56,"sourceCode":"// Write writes manifests to a file, a writer or a GCS bucket.\nfunc Write(manifests string, output string, manifestOut io.Writer) error {\n\tswitch {\n\tcase output == \"\":\n\t\t_, err := fmt.Fprintln(manifestOut, manifests)\n\t\treturn err\n\tcase strings.HasPrefix(output, gcsPrefix):\n\t\ttempDir, err := os.MkdirTemp(\"\", manifestsStagingFolder)\n\t\tif err != nil {\n\t\t\treturn writeErr(fmt.Errorf(\"failed to create the tmp directory: %w\", err))\n\t\t}\n\t\tdefer os.RemoveAll(tempDir)\n\t\ttempFile := filepath.Join(tempDir, renderedManifestsStagingFile)\n\t\tif err := dumpToFile(manifests, tempFile); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tgcs := client.Native{}\n\t\tif err := gcs.UploadFile(context.Background(), tempFile, output); err != nil {\n\t\t\treturn writeErr(fmt.Errorf(\"failed to copy rendered manifests to GCS: %w\", err))\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\treturn dumpToFile(manifests, output)\n\t}\n}\n\nfunc dumpToFile(manifests string, filepath string) error {\n\tf, err := os.Create(filepath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"opening file for writing manifests: %w\", err)\n\t}\n\tdefer f.Close()\n\t_, err = f.WriteString(manifests + \"\\n\")\n\treturn err\n}\n","sourceCodeStart":38,"sourceCodeEnd":73,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/kubernetes/manifest/util.go#L38-L73","documentation":"After staging rendered manifests in a temp file, Write uploads them to the gs:// destination via client.Native{}.UploadFile. Any GCS API failure (auth, bucket missing, permissions, network) is wrapped by writeErr as 'failed to copy rendered manifests to GCS'.","triggerScenarios":"Calling Write with output='gs://bucket/path' when UploadFile fails: unauthenticated gcloud session, nonexistent bucket, lacking storage.objects.create permission, or network error.","commonSituations":"CI without Application Default Credentials; typo in bucket name; service account missing roles/storage.objectAdmin on the bucket; private buckets from a different project.","solutions":["Authenticate: run `gcloud auth application-default login` (local) or attach a service account with Storage Object Admin to CI","Verify the bucket exists and the output gs:// path is correct (`gsutil ls` on the bucket)","Grant storage.objects.create permission on the bucket to the acting identity, then retry"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"creds, err := google.FindDefaultCredentials(ctx, \"https://www.googleapis.com/auth/devstorage.read_write\")\nif err != nil {\n    return fmt.Errorf(\"no GCS credentials: %w\", err)\n}\n// and verify bucket access:\n_, err = storageClient.Bucket(bucket).Attrs(ctx)","typeGuard":null,"tryCatchPattern":"if err != nil {\n    var gErr *googleapi.Error\n    if errors.As(err, &gErr) {\n        switch gErr.Code {\n        case 401, 403: // re-authenticate / fix IAM\n        case 404:     // check bucket name\n        }\n    }\n    return err\n}","preventionTips":["Authenticate with `gcloud auth application-default login` or a workload service account","Grant the identity storage.objects.create on the target bucket","Validate the gs:// path and bucket existence before rendering to GCS"],"tags":["gcs","cloud-storage","authentication","output"],"backgroundTag":"gcs-upload-failed","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}