weaviate/weaviate · error

close writer for file: %v

Error message

close writer for file: %v

What it means

With the GCS SDK, writer.Close() finalizes the resumable upload — this is where the object actually becomes visible, so most server-side rejections surface here rather than during Write. A Close error is wrapped as 'close writer for file: <objectName>' and means the object was NOT persisted despite Write returning nil.

Source

Thrown at modules/backup-gcs/client.go:330

func (g *gcsClient) PutObject(ctx context.Context, backupID, key, overrideBucket, overridePath string, byes []byte) error {
	bucket, err := g.findBucket(ctx, overrideBucket)
	if err != nil {
		return errors.Wrap(err, "find bucket")
	}

	objectName := g.makeObjectName(overridePath, []string{backupID, key})
	obj := bucket.Object(objectName)
	writer := obj.NewWriter(ctx)
	writer.ContentType = "application/octet-stream"
	writer.Metadata = map[string]string{
		"backup-id": backupID,
	}
	if _, err := writer.Write(byes); err != nil {
		return errors.Wrapf(err, "write file: %v", objectName)
	}
	if err := writer.Close(); err != nil {
		return errors.Wrapf(err, "close writer for file: %v", objectName)
	}

	metric, err := monitoring.GetMetrics().BackupStoreDataTransferred.GetMetricWithLabelValues("backup-gcs", "class")
	if err == nil {
		metric.Add(float64(len(byes)))
	}

	return nil
}

func (g *gcsClient) Initialize(ctx context.Context, backupID, overrideBucket, overridePath string) error {
	if _, err := g.resolveBucketName(overrideBucket); err != nil {
		return err
	}

	if g.config.SkipAccessCheck {
		return nil
	}

View on GitHub (pinned to 75aa4b6d11)

Solutions

  1. Retry the backup operation — a failed Close means the object does not exist, so re-uploading is safe
  2. Verify the service account has storage.objects.create AND storage.objects.delete/update (Storage Object Admin covers it)
  3. Check quota/storage-class settings on the bucket and project
  4. Increase context timeout if the final flush of large objects exceeds the deadline; check the wrapped error for the HTTP status
Defensive patterns

Strategy: retry

Type guard

func uploadFinalized(err error) bool {
    // nil error from Close means the object exists
    return err == nil
}

Try / catch

if err := module.Initialize(ctx, backupID, bucket, path); err != nil {
    if strings.Contains(err.Error(), "close writer") {
        // finalize failed: object not created; retry entire operation
    }
}
// GCS SDK side: always check Close, never ignore it
w := obj.NewWriter(ctx)
w.Write(data)
if err := w.Close(); err != nil { return err }

Prevention

When it happens

Trigger: writer.Close() fails: GCS returns 403 on finalize (permission checked late), quota exceeded, checksum validation failure, context deadline hit while flushing the final chunk, or 503 from GCS.

Common situations: Service account with create-but-no-finalize permissions; project nearing storage quota; short deadlines where the final flush of a large file exceeds the remaining time; transient GCS incidents during backup.

Related errors


AI-assisted analysis of weaviate/weaviate@75aa4b6d11 (2026-09-04). Data as JSON: /api/errors/dc16e6b9526cf533. Report an issue: GitHub.