Skip to content

CopyObject/UploadPartCopy fails if the source object contains special characters. #1357

@nidor1998

Description

@nidor1998

Describe the bug

CopyObject/UploadPartCopy fails with a NoSuchKey error if the source object contains special characters.

According to AWS documentation, CopyObject/UploadPartCopy's x-amz-copy-source parameter should be URL encoded.

https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html#API_CopyObject_RequestSyntax
https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html#API_UploadPartCopy_RequestSyntax

However the SDK does not URL encode the source object key before sending the request to S3.

For example, if the source object key is etc/alternatives/c++, the SDK fails with a NoSuchKey error.
etc/alternatives/c++ should be encoded as etc/alternatives/c%2B%2B.

Regression Issue

  • Select this option if this issue appears to be a regression.

Expected Behavior

aws_sdk_s3::Client::copy_object/upload_part_copy should succeed even if the source object key contains special characters that need to be URL encoded.

Current Behavior

aws_sdk_s3::Client::copy_object/upload_part_copy fails with a NoSuchKey error if the source object contains special characters.

Reproduction Steps

Please run the following code.

use aws_config::BehaviorVersion;
use aws_sdk_s3::primitives::ByteStream;
use tracing_subscriber::filter::EnvFilter;
use tracing_subscriber::fmt::Subscriber;

#[tokio::main]
async fn main() -> Result<(), aws_sdk_s3::Error> {
    Subscriber::builder()
        .with_env_filter(EnvFilter::new("aws_sigv4=trace"))
        .init();

    let config = aws_config::defaults(BehaviorVersion::latest()).load().await;
    let client = aws_sdk_s3::Client::new(&config);

    let content = "Dummy content";
    let src_bucket = "XXXXX";
    let src_key = "etc/alternatives/c++";
    let dst_bucket = "YYYYY";
    let dst_key = "etc/alternatives/c++";

    client
        .put_object()
        .bucket(src_bucket)
        .key(src_key)
        .body(ByteStream::from_static(content.as_bytes()))
        .send()
        .await?;

    let copy_source = format!("{}/{}", src_bucket, src_key);
    client
        .copy_object()
        .bucket(dst_bucket)
        .key(dst_key)
        .copy_source(copy_source)
        .send()
        .await?;

    Ok(())
}

Possible Solution

URL encoded x-amz-copy-source parameter before sending the request to S3.

Additional Information/Context

No response

Version

$ cargo tree | grep aws-
├── aws-config v1.8.6
│   ├── aws-credential-types v1.2.6
│   │   ├── aws-smithy-async v1.2.5
│   │   ├── aws-smithy-runtime-api v1.9.0
│   │   │   ├── aws-smithy-async v1.2.5 (*)
│   │   │   ├── aws-smithy-types v1.3.2
│   │   ├── aws-smithy-types v1.3.2 (*)
│   ├── aws-runtime v1.5.10
│   │   ├── aws-credential-types v1.2.6 (*)
│   │   ├── aws-sigv4 v1.3.4
│   │   │   ├── aws-credential-types v1.2.6 (*)
│   │   │   ├── aws-smithy-eventstream v0.60.11
│   │   │   │   ├── aws-smithy-types v1.3.2 (*)
│   │   │   ├── aws-smithy-http v0.62.3
│   │   │   │   ├── aws-smithy-eventstream v0.60.11 (*)
│   │   │   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   │   │   ├── aws-smithy-types v1.3.2 (*)
│   │   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   │   ├── aws-smithy-types v1.3.2 (*)
│   │   ├── aws-smithy-async v1.2.5 (*)
│   │   ├── aws-smithy-eventstream v0.60.11 (*)
│   │   ├── aws-smithy-http v0.62.3 (*)
│   │   ├── aws-smithy-runtime v1.9.2
│   │   │   ├── aws-smithy-async v1.2.5 (*)
│   │   │   ├── aws-smithy-http v0.62.3 (*)
│   │   │   ├── aws-smithy-http-client v1.1.1
│   │   │   │   ├── aws-smithy-async v1.2.5 (*)
│   │   │   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   │   │   ├── aws-smithy-types v1.3.2 (*)
│   │   │   │   │   │   ├── aws-lc-rs v1.14.0
│   │   │   │   │   │   │   ├── aws-lc-sys v0.31.0
│   │   │   │   │   │   │   ├── aws-lc-rs v1.14.0 (*)
│   │   │   ├── aws-smithy-observability v0.1.3
│   │   │   │   └── aws-smithy-runtime-api v1.9.0 (*)
│   │   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   │   ├── aws-smithy-types v1.3.2 (*)
│   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   ├── aws-smithy-types v1.3.2 (*)
│   │   ├── aws-types v1.3.8
│   │   │   ├── aws-credential-types v1.2.6 (*)
│   │   │   ├── aws-smithy-async v1.2.5 (*)
│   │   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   │   ├── aws-smithy-types v1.3.2 (*)
│   ├── aws-sdk-sso v1.84.0
│   │   ├── aws-credential-types v1.2.6 (*)
│   │   ├── aws-runtime v1.5.10 (*)
│   │   ├── aws-smithy-async v1.2.5 (*)
│   │   ├── aws-smithy-http v0.62.3 (*)
│   │   ├── aws-smithy-json v0.61.5
│   │   │   └── aws-smithy-types v1.3.2 (*)
│   │   ├── aws-smithy-runtime v1.9.2 (*)
│   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   ├── aws-smithy-types v1.3.2 (*)
│   │   ├── aws-types v1.3.8 (*)
│   ├── aws-sdk-ssooidc v1.85.0
│   │   ├── aws-credential-types v1.2.6 (*)
│   │   ├── aws-runtime v1.5.10 (*)
│   │   ├── aws-smithy-async v1.2.5 (*)
│   │   ├── aws-smithy-http v0.62.3 (*)
│   │   ├── aws-smithy-json v0.61.5 (*)
│   │   ├── aws-smithy-runtime v1.9.2 (*)
│   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   ├── aws-smithy-types v1.3.2 (*)
│   │   ├── aws-types v1.3.8 (*)
│   ├── aws-sdk-sts v1.86.0
│   │   ├── aws-credential-types v1.2.6 (*)
│   │   ├── aws-runtime v1.5.10 (*)
│   │   ├── aws-smithy-async v1.2.5 (*)
│   │   ├── aws-smithy-http v0.62.3 (*)
│   │   ├── aws-smithy-json v0.61.5 (*)
│   │   ├── aws-smithy-query v0.60.7
│   │   │   ├── aws-smithy-types v1.3.2 (*)
│   │   ├── aws-smithy-runtime v1.9.2 (*)
│   │   ├── aws-smithy-runtime-api v1.9.0 (*)
│   │   ├── aws-smithy-types v1.3.2 (*)
│   │   ├── aws-smithy-xml v0.60.10
│   │   ├── aws-types v1.3.8 (*)
│   ├── aws-smithy-async v1.2.5 (*)
│   ├── aws-smithy-http v0.62.3 (*)
│   ├── aws-smithy-json v0.61.5 (*)
│   ├── aws-smithy-runtime v1.9.2 (*)
│   ├── aws-smithy-runtime-api v1.9.0 (*)
│   ├── aws-smithy-types v1.3.2 (*)
│   ├── aws-types v1.3.8 (*)
├── aws-sdk-s3 v1.106.0
│   ├── aws-credential-types v1.2.6 (*)
│   ├── aws-runtime v1.5.10 (*)
│   ├── aws-sigv4 v1.3.4 (*)
│   ├── aws-smithy-async v1.2.5 (*)
│   ├── aws-smithy-checksums v0.63.8
│   │   ├── aws-smithy-http v0.62.3 (*)
│   │   ├── aws-smithy-types v1.3.2 (*)
│   ├── aws-smithy-eventstream v0.60.11 (*)
│   ├── aws-smithy-http v0.62.3 (*)
│   ├── aws-smithy-json v0.61.5 (*)
│   ├── aws-smithy-runtime v1.9.2 (*)
│   ├── aws-smithy-runtime-api v1.9.0 (*)
│   ├── aws-smithy-types v1.3.2 (*)
│   ├── aws-smithy-xml v0.60.10 (*)
│   ├── aws-types v1.3.8 (*)
$

Environment details (OS name and version, etc.)

Linux XXXX 6.8.0-79-generic #79-Ubuntu SMP PREEMPT_DYNAMIC Tue Aug 12 14:42:46 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

Logs

2025-09-16T00:25:57.465803Z TRACE aws_sigv4::http_request::sign: canonical_request=PUT
/etc/alternatives/c%2B%2B
x-id=CopyObject
host:17f10050-97d7-4ba6-bb84-552000698ab7.s3.ap-northeast-1.amazonaws.com
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-copy-source:2ef073f2-f779-4361-956d-052ad0e6e79b/etc/alternatives/c++
x-amz-date:20250916T002557Z
x-amz-user-agent:aws-sdk-rust/1.3.8 ua/2.1 api/s3/1.106.0 os/macos lang/rust/1.89.0 m/E,n md/http#hyper-1.x

host;x-amz-content-sha256;x-amz-copy-source;x-amz-date;x-amz-user-agent
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


Error: Unhandled(Unhandled { source: ErrorMetadata { code: Some("NoSuchKey"), message: Some("The specified key does not exist."), extras: Some({"s3_extended_request_id": "nJ0AmnXcJmNbA4F/9WobnaZIgtlH0ac9LWfjFd8s6mnC6e2Ss3Py9ECCDt2U1sf2PAEiZZCQVMU=", "aws_request_id": "AD5WYN1CAMK6RP27"}) }, meta: ErrorMetadata { code: Some("NoSuchKey"), message: Some("The specified key does not exist."), extras: Some({"s3_extended_request_id": "nJ0AmnXcJmNbA4F/9WobnaZIgtlH0ac9LWfjFd8s6mnC6e2Ss3Py9ECCDt2U1sf2PAEiZZCQVMU=", "aws_request_id": "AD5WYN1CAMK6RP27"}) } })

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