{"record":{"id":"9e089233364e1c14","repo":"googleapis/mcp-toolbox","slug":"failed-to-write-content-to-object-q-in-bucket-q","errorCode":null,"errorMessage":"failed to write content to object %q in bucket %q: %w","messagePattern":"failed to write content to object %q in bucket %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/cloudstorage/cloudstorage.go","lineNumber":522,"sourceCode":"}\n\n// WriteObject writes text content directly into a GCS object. When contentType\n// is empty, the writer's ContentType is left unset so Cloud Storage detects it\n// from the first 512 bytes. The returned contentType is the post-Close value\n// from w.Attrs(), i.e. what GCS actually recorded.\nfunc (s *Source) WriteObject(ctx context.Context, bucket, object, content, contentType string) (map[string]any, error) {\n\tif err := s.validateBucket(bucket); err != nil {\n\t\treturn nil, err\n\t}\n\tw := s.client.Bucket(bucket).Object(object).NewWriter(ctx)\n\tif contentType != \"\" {\n\t\tw.ContentType = contentType\n\t}\n\n\tn, err := io.WriteString(w, content)\n\tif err != nil {\n\t\t_ = w.Close()\n\t\treturn nil, fmt.Errorf(\"failed to write content to object %q in bucket %q: %w\", object, bucket, err)\n\t}\n\tif err := w.Close(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to finalize write to %q/%q: %w\", bucket, object, err)\n\t}\n\n\tattrs := w.Attrs()\n\tfinalContentType := \"\"\n\tif attrs != nil {\n\t\tfinalContentType = attrs.ContentType\n\t}\n\treturn map[string]any{\n\t\t\"bucket\":      bucket,\n\t\t\"object\":      object,\n\t\t\"bytes\":       n,\n\t\t\"contentType\": finalContentType,\n\t}, nil\n}\n","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/cloudstorage/cloudstorage.go#L504-L540","documentation":"WriteObject writes a string to a GCS object through storage.Writer; this error wraps a failure returned by io.WriteString BEFORE Close is attempted. It means data could not be handed to the underlying upload stream — typically context cancellation, a broken HTTP body, or an already-failed writer — so the object was never finalized.","triggerScenarios":"Calling WriteObject(bucket, object, content, contentType) where io.WriteString returns an error: ctx cancelled/expired during the write, GCS returned an error on the first request flush, or the writer's internal pipe broke (e.g. authentication failure surfaced at first write).","commonSituations":"Very large payloads exceeding request deadlines, cancelled HTTP requests from MCP clients, credential expiry mid-request (401 surfaced at write), writing to a bucket whose location/permissions reject the stream.","solutions":["Check the wrapped error for context cancellation: create a fresh context with an adequate timeout and retry the WriteObject call.","Verify credentials are valid and not expired (gcloud auth / ADC configuration); 401/403 surfaces at first write for small payloads.","Confirm the service account has storage.objects.create on the bucket.","For very large content, prefer UploadObject from a temp file or raise the context deadline.","Check bucket existence and org policy restrictions before writing."],"exampleFix":"// before: single long deadline for everything\nctx := context.Background()\n// after: bounded deadline sized for the payload\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)\ndefer cancel()\n_, err := src.WriteObject(ctx, bucket, object, content, \"text/plain\")\nif errors.Is(err, context.DeadlineExceeded) {\n    // retry with larger timeout or chunk the content\n}","handlingStrategy":"validation","validationCode":"// Go: validate before WriteObject\nfunc precheckWrite(ctx context.Context, src *cloudstorage.Source, bucket, object, content string) error {\n    if content == \"\" {\n        return errors.New(\"refusing to write empty content\")\n    }\n    if _, err := src.Client.Bucket(bucket).Attrs(ctx); err != nil {\n        return fmt.Errorf(\"bucket %q unavailable: %w\", bucket, err)\n    }\n    return nil\n}","typeGuard":"// Go: detect context issues before/at write time\nfunc isContextFailure(err error) bool {\n    return errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)\n}","tryCatchPattern":"_, err := src.WriteObject(ctx, bucket, object, content, \"application/json\")\nif err != nil {\n    if isContextFailure(err) {\n        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\n        defer cancel()\n        _, err = src.WriteObject(ctx, bucket, object, content, \"application/json\")\n    }\n    if err != nil {\n        return fmt.Errorf(\"write to gs://%s/%s failed: %w\", bucket, object, err)\n    }\n}","preventionTips":["Size context timeouts to the payload; string writes buffer in memory so huge payloads need longer deadlines or UploadObject.","Keep ADC/credentials refreshed; expired tokens surface as write failures on small payloads.","Validate bucket name format (no gs:// prefix, valid DNS name) before calling.","Prefer streaming UploadObject for content above a few MB.","Wrap calls so the underlying %w cause is always logged, never swallowed."],"tags":["gcs","write","context-cancelled","network"],"backgroundTag":"gcs-object-write-failed","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}