Skip to content

Copy/move operations return no error but destination blob is not created (copyBlob / move) #22

@rodrigoj-avantpage

Description

@rodrigoj-avantpage

Summary

The methods move() and copy() are not functioning as expected. When invoked, both methods execute without raising any errors; however, the files are neither moved nor copied from the source to the destination. Additionally, when move() is called, the source file is deleted despite the file not being transferred.

Versions

Version
PHP version 8.4.x
Service blob, file, queue, table
azure-storage-php version 1.4.0

Self-enclosed code snippet for reproduction

<?php
require 'vendor/autoload.php';

use MicrosoftAzure\Storage\Blob\BlobRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;

$connectionString = 'DefaultEndpointsProtocol=https;AccountName=MY_ACCOUNT;AccountKey=MY_KEY;EndpointSuffix=core.windows.net';
$client = BlobRestProxy::createBlobService($connectionString);

// Adjust values for your account
$srcContainer = 'source-container';
$srcBlob = 'example.pdf';
$destContainer = 'dest-container';
$destBlob = 'example.pdf';

echo "=== COPY (same account) ===\n";
try {
    $copyResult = $client->copyBlob($destContainer, $destBlob, $srcContainer, $srcBlob);
    echo 'copyBlob returned: copyId=' . ($copyResult->getCopyId() ?? 'null') .
         ' copyStatus=' . ($copyResult->getCopyStatus() ?? 'null') . PHP_EOL;
} catch (ServiceException $se) {
    echo 'ServiceException on copyBlob: ' . $se->getCode() . ' - ' . $se->getMessage() . PHP_EOL;
} catch (\Throwable $e) {
    echo 'Error on copyBlob: ' . $e->getMessage() . PHP_EOL;
}

// Check destination existence
try {
    $client->getBlobProperties($destContainer, $destBlob);
    echo "DESTINATION EXISTS: {$destContainer}/{$destBlob}\n";
} catch (ServiceException $se) {
    echo "DESTINATION MISSING after copy (HTTP {$se->getCode()}): {$se->getMessage()}\n";
}

echo "\n=== MOVE (copy + delete origin) ===\n";
$srcContainerM = $srcContainer;
$srcBlobM = 'file-to-move.pdf';
$destContainerM = $destContainer;
$destBlobM = 'file-to-move.pdf';

try {
    $copyResultM = $client->copyBlob($destContainerM, $destBlobM, $srcContainerM, $srcBlobM);
    echo 'copyBlob (move) returned: copyId=' . ($copyResultM->getCopyId() ?? 'null') .
         ' copyStatus=' . ($copyResultM->getCopyStatus() ?? 'null') . PHP_EOL;
} catch (ServiceException $se) {
    echo 'ServiceException on copyBlob (move): ' . $se->getCode() . ' - ' . $se->getMessage() . PHP_EOL;
    exit(1);
} catch (\Throwable $e) {
    echo 'Error on copyBlob (move): ' . $e->getMessage() . PHP_EOL;
    exit(1);
}

// Immediately try to delete origin (minimal test). Real flow should poll getBlobProperties on destination first.
try {
    $client->deleteBlob($srcContainerM, $srcBlobM);
    echo "deleteBlob succeeded for origin {$srcContainerM}/{$srcBlobM}\n";
} catch (ServiceException $se) {
    echo "ServiceException on deleteBlob: " . $se->getCode() . ' - ' . $se->getMessage() . PHP_EOL;
} catch (\Throwable $e) {
    echo 'Error on deleteBlob: ' . $e->getMessage() . PHP_EOL;
}

// Final destination check
try {
    $client->getBlobProperties($destContainerM, $destBlobM);
    echo "DESTINATION EXISTS after move: {$destContainerM}/{$destBlobM}\n";
} catch (ServiceException $se) {
    echo "DESTINATION MISSING after move (HTTP {$se->getCode()}): {$se->getMessage()}\n";
}

Expected behavior

copyBlob should either:

  1. return a copyId and a copyStatus that indicates operation progress (or success), and destination blob should exist after copy finishes, or
  2. throw a ServiceException with a descriptive HTTP status and message if the copy fails.

For move (copy+delete):

  1. The SDK should not silently fail to create the destination then delete the origin. At minimum, copy should fail or return clear copy state.

Actual behavior

  • copyBlob returns without throwing an exception.
  • copyResult->getCopyId() or getCopyStatus() are often null.
  • getBlobProperties on the destination frequently returns 404 (DESTINATION MISSING), but no exception was thrown by copyBlob.
  • The origin can be deleted in the move flow even though the destination is not present.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions