{"record":{"id":"8734d7b3250d6626","repo":"VictoriaMetrics/VictoriaMetrics","slug":"cannot-perform-server-side-copying-from-s-to-s","errorCode":null,"errorMessage":"cannot perform server-side copying from %s to %s: both of them must be AZBlob","messagePattern":"cannot perform server-side copying from (.+?) to (.+?): both of them must be AZBlob","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/backup/azremote/azblob.go","lineNumber":212,"sourceCode":"\treturn parts, nil\n}\n\n// DeletePart deletes part p from fs.\nfunc (fs *FS) DeletePart(p common.Part) error {\n\treturn fs.delete(p.RemotePath(fs.Dir))\n}\n\n// RemoveEmptyDirs recursively removes empty dirs in fs.\nfunc (fs *FS) RemoveEmptyDirs() error {\n\t// Blob storage has no directories, so nothing to remove.\n\treturn nil\n}\n\n// CopyPart copies p from srcFS to fs.\nfunc (fs *FS) CopyPart(srcFS common.OriginFS, p common.Part) error {\n\tsrc, ok := srcFS.(*FS)\n\tif !ok {\n\t\treturn fmt.Errorf(\"cannot perform server-side copying from %s to %s: both of them must be AZBlob\", srcFS, fs)\n\t}\n\n\tsbc := src.client.NewBlobClient(p.RemotePath(src.Dir))\n\tdbc := fs.clientForPart(p)\n\n\t// In order to support copy of files larger than 256MB, we need to use the async copy\n\t// Ref: https://learn.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url\n\t_, err := dbc.StartCopyFromURL(fs.ctx, sbc.URL(), &blob.StartCopyFromURLOptions{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot start async copy %q from %s to %s: %w\", p.Path, src, fs, err)\n\t}\n\n\tvar copyStatus *blob.CopyStatusType\n\tvar copyStatusDescription *string\n\tfor {\n\t\tr, err := dbc.GetProperties(fs.ctx, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to check copy status, cannot get properties of %q at %s: %w\", p.Path, fs, err)","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/VictoriaMetrics/VictoriaMetrics/blob/5079fb58f1e8e62113f90c945ad71586c797d770/lib/backup/azremote/azblob.go#L194-L230","documentation":"CopyPart performs Azure Blob server-side (async) copying, which requires both the source and destination filesystems to be the azremote AZBlob FS implementation. The library type-asserts srcFS to *azremote.FS and throws this error when the source is a different storage backend (e.g. S3 or GCS), because StartCopyFromURL only works between Azure blobs.","triggerScenarios":"Calling CopyPart with a srcFS that is not the AZBlob FS wrapper, e.g. mixing S3-backed and AZBlob-backed origins in a backup/restore pipeline.","commonSituations":"Migration jobs between cloud providers where the source is S3/GCS and the destination is Azure; misconfigured backup destination so a non-Azure FS is passed; tests or custom OriginFS implementations that aren't backed by Azure Blob.","solutions":["Ensure both srcFS and fs are created via the AZBlob (azremote) filesystem implementation.","If the source cannot be Azure Blob, download the part from the source and upload it to the destination instead of server-side copy.","Check your backup/storage configuration so both origin and destination point to the same Azure storage backend type."],"exampleFix":"// before\nerr := dstFS.CopyPart(s3FS, part) // s3FS is *s3remote.FS\n// after\nerr := dstFS.CopyPart(azFS, part) // both must be *azremote.FS","handlingStrategy":"type-guard","validationCode":"// before calling CopyPart\nazFS, ok := srcFS.(*azremote.FS)\nif !ok {\n    return fmt.Errorf(\"server-side copy unsupported for %T; use download+upload fallback\", srcFS)\n}","typeGuard":"func asAZBlobFS(fs common.OriginFS) (*azremote.FS, bool) {\n    f, ok := fs.(*azremote.FS)\n    return f, ok\n}","tryCatchPattern":"if err := dstFS.CopyPart(srcFS, part); err != nil && strings.Contains(err.Error(), \"both of them must be AZBlob\") {\n    // fall back to DownloadPart(srcFS) + UploadPart(dstFS)\n}","preventionTips":["Use the same storage backend type for origin and destination when relying on server-side copy","Type-check FS implementations at pipeline construction time, not at copy time","Implement a generic copy fallback (download+upload) for mixed-backend migrations"],"tags":["azure","azure-blob","type-assertion","unsupported-operation"],"backgroundTag":"incompatible-storage-backend","analyzedSha":"5079fb58f1e8e62113f90c945ad71586c797d770","analyzedAt":"2026-09-03T18:10:26.153Z","contentChangedAt":"2026-09-03T18:10:26.153Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}