Is there an existing issue for this?
Is this happening on an up to date version of Incus?
Current behavior
The new built-in S3 listener in Incus 7.0 is missing support for CopyObject. This causes a silent failure with a 0 byte file creation which may not be noticed by the user.
Manual reproduction (minimal curl):
# Prerequisites: a storage bucket with S3 credentials on a local-backed pool
# 1. Write a test object
curl -sk -X PUT \
--data-binary "hello-world" \
--aws-sigv4 "aws:amz:us-east-1:s3" \
-u "$ACCESS_KEY:$SECRET_KEY" \
"https://$S3_ENDPOINT/$BUCKET/test-source.txt"
# 2. CopyObject — should copy test-source.txt to test-copy.txt
curl -sk -X PUT \
--aws-sigv4 "aws:amz:us-east-1:s3" \
-u "$ACCESS_KEY:$SECRET_KEY" \
-H "x-amz-copy-source: /$BUCKET/test-source.txt" \
"https://$S3_ENDPOINT/$BUCKET/test-copy.txt" \
-D - -o /dev/null
# 3. Read back the copy — expect 11 bytes, get 0
curl -sk -X GET \
--aws-sigv4 "aws:amz:us-east-1:s3" \
-u "$ACCESS_KEY:$SECRET_KEY" \
"https://$S3_ENDPOINT/$BUCKET/test-copy.txt" \
-w "HTTP_CODE=%{http_code} SIZE=%{size_download}\n" -o /dev/null
Detailed info
Two bugs:
- Data loss: The destination object is written as 0 bytes instead of being copied from the source.
- Protocol-violating response: The Go AWS SDK (and likely other S3 clients) expects a non-empty XML response body and throws
SerializationError: empty response payload.
The bug is likely in the handleObject method in internal/server/storage/s3/local/server.go at lines 203–215
Line 209 dispatches all PUT requests to putObject without inspecting the x-amz-copy-source header. The S3 CopyObject API is defined as a PUT with that header set and an empty body.
| File |
Lines |
Role |
| internal/server/storage/s3/local/server.go |
203–215 |
handleObject dispatch — missing CopyObject branch |
| internal/server/storage/s3/local/object.go |
116–176 |
putObject — reads from r.Body, produces 0-byte file for CopyObject |
| internal/server/storage/s3/local/object.go |
137 |
io.Copy from r.Body — the specific line that writes 0 bytes |
| internal/server/storage/s3/local/meta.go |
17–24 |
objectMeta struct — metadata that would need copying |
| internal/server/storage/s3/local/meta.go |
69–110 |
loadOrInferMeta — reads source metadata |
| internal/server/storage/s3/types.go |
29–36 |
Error struct — used for error responses |
Expected behavior
Per the S3 CopyObject specification, a PUT with x-amz-copy-source should:
- Copy the source object's data to the destination key.
- Return HTTP 200 with an XML body.
As incus version 6.23 had a working implementation I suggest we should maintain this compatibility. I ran into the issue using incus integrated S3 bucket to store state of pulumi incus terraform provider bridge, after update to 7.0 it breaks.
Steps to reproduce
Self-contained reproduction script is provided: reproduce-incus-s3-copyobject.sh
./reproduce-incus-s3-copyobject.sh --pool <pool-name>
./reproduce-incus-s3-copyobject.sh --pool <pool-name> --remote <remote-name>
Incus system details
config:
core.bgp_address: 192.168.X.X:179
core.bgp_asn: "n"
core.bgp_routerid: 192.168.X.X
core.dns_address: 192.168.X.X:1053
core.https_address: '[::]:8443'
core.storage_buckets_address: :8444
api_extensions:
- storage_zfs_remove_snapshots
- container_host_shutdown_timeout
- container_stop_priority
- container_syscall_filtering
- auth_pki
- container_last_used_at
- etag
- patch
- usb_devices
- https_allowed_credentials
- image_compression_algorithm
- directory_manipulation
- container_cpu_time
- storage_zfs_use_refquota
- storage_lvm_mount_options
- network
- profile_usedby
- container_push
- container_exec_recording
- certificate_update
- container_exec_signal_handling
- gpu_devices
- container_image_properties
- migration_progress
- id_map
- network_firewall_filtering
- network_routes
- storage
- file_delete
- file_append
- network_dhcp_expiry
- storage_lvm_vg_rename
- storage_lvm_thinpool_rename
- network_vlan
- image_create_aliases
- container_stateless_copy
- container_only_migration
- storage_zfs_clone_copy
- unix_device_rename
- storage_lvm_use_thinpool
- storage_rsync_bwlimit
- network_vxlan_interface
- storage_btrfs_mount_options
- entity_description
- image_force_refresh
- storage_lvm_lv_resizing
- id_map_base
- file_symlinks
- container_push_target
- network_vlan_physical
- storage_images_delete
- container_edit_metadata
- container_snapshot_stateful_migration
- storage_driver_ceph
- storage_ceph_user_name
- resource_limits
- storage_volatile_initial_source
- storage_ceph_force_osd_reuse
- storage_block_filesystem_btrfs
- resources
- kernel_limits
- storage_api_volume_rename
- network_sriov
- console
- restrict_dev_incus
- migration_pre_copy
- infiniband
- dev_incus_events
- proxy
- network_dhcp_gateway
- file_get_symlink
- network_leases
- unix_device_hotplug
- storage_api_local_volume_handling
- operation_description
- clustering
- event_lifecycle
- storage_api_remote_volume_handling
- nvidia_runtime
- container_mount_propagation
- container_backup
- dev_incus_images
- container_local_cross_pool_handling
- proxy_unix
- proxy_udp
- clustering_join
- proxy_tcp_udp_multi_port_handling
- network_state
- proxy_unix_dac_properties
- container_protection_delete
- unix_priv_drop
- pprof_http
- proxy_haproxy_protocol
- network_hwaddr
- proxy_nat
- network_nat_order
- container_full
- backup_compression
- nvidia_runtime_config
- storage_api_volume_snapshots
- storage_unmapped
- projects
- network_vxlan_ttl
- container_incremental_copy
- usb_optional_vendorid
- snapshot_scheduling
- snapshot_schedule_aliases
- container_copy_project
- clustering_server_address
- clustering_image_replication
- container_protection_shift
- snapshot_expiry
- container_backup_override_pool
- snapshot_expiry_creation
- network_leases_location
- resources_cpu_socket
- resources_gpu
- resources_numa
- kernel_features
- id_map_current
- event_location
- storage_api_remote_volume_snapshots
- network_nat_address
- container_nic_routes
- cluster_internal_copy
- seccomp_notify
- lxc_features
- container_nic_ipvlan
- network_vlan_sriov
- storage_cephfs
- container_nic_ipfilter
- resources_v2
- container_exec_user_group_cwd
- container_syscall_intercept
- container_disk_shift
- storage_shifted
- resources_infiniband
- daemon_storage
- instances
- image_types
- resources_disk_sata
- clustering_roles
- images_expiry
- resources_network_firmware
- backup_compression_algorithm
- ceph_data_pool_name
- container_syscall_intercept_mount
- compression_squashfs
- container_raw_mount
- container_nic_routed
- container_syscall_intercept_mount_fuse
- container_disk_ceph
- virtual-machines
- image_profiles
- clustering_architecture
- resources_disk_id
- storage_lvm_stripes
- vm_boot_priority
- unix_hotplug_devices
- api_filtering
- instance_nic_network
- clustering_sizing
- firewall_driver
- projects_limits
- container_syscall_intercept_hugetlbfs
- limits_hugepages
- container_nic_routed_gateway
- projects_restrictions
- custom_volume_snapshot_expiry
- volume_snapshot_scheduling
- trust_ca_certificates
- snapshot_disk_usage
- clustering_edit_roles
- container_nic_routed_host_address
- container_nic_ipvlan_gateway
- resources_usb_pci
- resources_cpu_threads_numa
- resources_cpu_core_die
- api_os
- container_nic_routed_host_table
- container_nic_ipvlan_host_table
- container_nic_ipvlan_mode
- resources_system
- images_push_relay
- network_dns_search
- container_nic_routed_limits
- instance_nic_bridged_vlan
- network_state_bond_bridge
- usedby_consistency
- custom_block_volumes
- clustering_failure_domains
- resources_gpu_mdev
- console_vga_type
- projects_limits_disk
- network_type_macvlan
- network_type_sriov
- container_syscall_intercept_bpf_devices
- network_type_ovn
- projects_networks
- projects_networks_restricted_uplinks
- custom_volume_backup
- backup_override_name
- storage_rsync_compression
- network_type_physical
- network_ovn_external_subnets
- network_ovn_nat
- network_ovn_external_routes_remove
- tpm_device_type
- storage_zfs_clone_copy_rebase
- gpu_mdev
- resources_pci_iommu
- resources_network_usb
- resources_disk_address
- network_physical_ovn_ingress_mode
- network_ovn_dhcp
- network_physical_routes_anycast
- projects_limits_instances
- network_state_vlan
- instance_nic_bridged_port_isolation
- instance_bulk_state_change
- network_gvrp
- instance_pool_move
- gpu_sriov
- pci_device_type
- storage_volume_state
- network_acl
- migration_stateful
- disk_state_quota
- storage_ceph_features
- projects_compression
- projects_images_remote_cache_expiry
- certificate_project
- network_ovn_acl
- projects_images_auto_update
- projects_restricted_cluster_target
- images_default_architecture
- network_ovn_acl_defaults
- gpu_mig
- project_usage
- network_bridge_acl
- warnings
- projects_restricted_backups_and_snapshots
- clustering_join_token
- clustering_description
- server_trusted_proxy
- clustering_update_cert
- storage_api_project
- server_instance_driver_operational
- server_supported_storage_drivers
- event_lifecycle_requestor_address
- resources_gpu_usb
- clustering_evacuation
- network_ovn_nat_address
- network_bgp
- network_forward
- custom_volume_refresh
- network_counters_errors_dropped
- metrics
- image_source_project
- clustering_config
- network_peer
- linux_sysctl
- network_dns
- ovn_nic_acceleration
- certificate_self_renewal
- instance_project_move
- storage_volume_project_move
- cloud_init
- network_dns_nat
- database_leader
- instance_all_projects
- clustering_groups
- ceph_rbd_du
- instance_get_full
- qemu_metrics
- gpu_mig_uuid
- event_project
- clustering_evacuation_live
- instance_allow_inconsistent_copy
- network_state_ovn
- storage_volume_api_filtering
- image_restrictions
- storage_zfs_export
- network_dns_records
- storage_zfs_reserve_space
- network_acl_log
- storage_zfs_blocksize
- metrics_cpu_seconds
- instance_snapshot_never
- certificate_token
- instance_nic_routed_neighbor_probe
- event_hub
- agent_nic_config
- projects_restricted_intercept
- metrics_authentication
- images_target_project
- images_all_projects
- cluster_migration_inconsistent_copy
- cluster_ovn_chassis
- container_syscall_intercept_sched_setscheduler
- storage_lvm_thinpool_metadata_size
- storage_volume_state_total
- instance_file_head
- instances_nic_host_name
- image_copy_profile
- container_syscall_intercept_sysinfo
- clustering_evacuation_mode
- resources_pci_vpd
- qemu_raw_conf
- storage_cephfs_fscache
- network_load_balancer
- vsock_api
- instance_ready_state
- network_bgp_holdtime
- storage_volumes_all_projects
- metrics_memory_oom_total
- storage_buckets
- storage_buckets_create_credentials
- metrics_cpu_effective_total
- projects_networks_restricted_access
- storage_buckets_local
- loki
- acme
- internal_metrics
- cluster_join_token_expiry
- remote_token_expiry
- init_preseed
- storage_volumes_created_at
- cpu_hotplug
- projects_networks_zones
- network_txqueuelen
- cluster_member_state
- instances_placement_scriptlet
- storage_pool_source_wipe
- zfs_block_mode
- instance_generation_id
- disk_io_cache
- amd_sev
- storage_pool_loop_resize
- migration_vm_live
- ovn_nic_nesting
- oidc
- network_ovn_l3only
- ovn_nic_acceleration_vdpa
- cluster_healing
- instances_state_total
- auth_user
- security_csm
- instances_rebuild
- numa_cpu_placement
- custom_volume_iso
- network_allocations
- zfs_delegate
- storage_api_remote_volume_snapshot_copy
- operations_get_query_all_projects
- metadata_configuration
- syslog_socket
- event_lifecycle_name_and_project
- instances_nic_limits_priority
- disk_initial_volume_configuration
- operation_wait
- image_restriction_privileged
- cluster_internal_custom_volume_copy
- disk_io_bus
- storage_cephfs_create_missing
- instance_move_config
- ovn_ssl_config
- certificate_description
- disk_io_bus_virtio_blk
- loki_config_instance
- instance_create_start
- clustering_evacuation_stop_options
- boot_host_shutdown_action
- agent_config_drive
- network_state_ovn_lr
- image_template_permissions
- storage_bucket_backup
- storage_lvm_cluster
- shared_custom_block_volumes
- auth_tls_jwt
- oidc_claim
- device_usb_serial
- numa_cpu_balanced
- image_restriction_nesting
- network_integrations
- instance_memory_swap_bytes
- network_bridge_external_create
- network_zones_all_projects
- storage_zfs_vdev
- container_migration_stateful
- profiles_all_projects
- instances_scriptlet_get_instances
- instances_scriptlet_get_cluster_members
- instances_scriptlet_get_project
- network_acl_stateless
- instance_state_started_at
- networks_all_projects
- network_acls_all_projects
- storage_buckets_all_projects
- resources_load
- instance_access
- project_access
- projects_force_delete
- resources_cpu_flags
- disk_io_bus_cache_filesystem
- instance_oci
- clustering_groups_config
- instances_lxcfs_per_instance
- clustering_groups_vm_cpu_definition
- disk_volume_subpath
- projects_limits_disk_pool
- network_ovn_isolated
- qemu_raw_qmp
- network_load_balancer_health_check
- oidc_scopes
- network_integrations_peer_name
- qemu_scriptlet
- instance_auto_restart
- storage_lvm_metadatasize
- ovn_nic_promiscuous
- ovn_nic_ip_address_none
- instances_state_os_info
- network_load_balancer_state
- instance_nic_macvlan_mode
- storage_lvm_cluster_create
- network_ovn_external_interfaces
- instances_scriptlet_get_instances_count
- cluster_rebalance
- custom_volume_refresh_exclude_older_snapshots
- storage_initial_owner
- storage_live_migration
- instance_console_screenshot
- image_import_alias
- authorization_scriptlet
- console_force
- network_ovn_state_addresses
- network_bridge_acl_devices
- instance_debug_memory
- init_preseed_storage_volumes
- init_preseed_profile_project
- instance_nic_routed_host_address
- instance_smbios11
- api_filtering_extended
- acme_dns01
- security_iommu
- network_ipv4_dhcp_routes
- network_state_ovn_ls
- network_dns_nameservers
- acme_http01_port
- network_ovn_ipv4_dhcp_expiry
- instance_state_cpu_time
- network_io_bus
- disk_io_bus_usb
- storage_driver_linstor
- instance_oci_entrypoint
- network_address_set
- server_logging
- network_forward_snat
- memory_hotplug
- instance_nic_routed_host_tables
- instance_publish_split
- init_preseed_certificates
- custom_volume_sftp
- network_ovn_external_nic_address
- network_physical_gateway_hwaddr
- backup_s3_upload
- snapshot_manual_expiry
- resources_cpu_address_sizes
- disk_attached
- limits_memory_hotplug
- disk_wwn
- server_logging_webhook
- storage_driver_truenas
- container_disk_tmpfs
- instance_limits_oom
- backup_override_config
- network_ovn_tunnels
- init_preseed_cluster_groups
- usb_attached
- backup_iso
- instance_systemd_credentials
- cluster_group_usedby
- bpf_token_delegation
- file_storage_volume
- network_hwaddr_pattern
- storage_volume_full
- storage_bucket_full
- device_pci_firmware
- resources_serial
- ovn_nic_limits
- storage_lvmcluster_qcow2
- oidc_allowed_subnets
- file_delete_force
- nic_sriov_select_ext
- network_zones_dns_contact
- nic_attached_connected
- nic_sriov_security_trusted
- direct_backup
- instance_snapshot_disk_only_restore
- unix_hotplug_pci
- cluster_evacuating_restoring
- projects_restricted_image_servers
- storage_lvmcluster_size
- authorization_scriptlet_cert
- lvmcluster_remove_snapshots
- daemon_storage_logs
- instances_debug_repair
- network_io_bus_ovn
- dependent
- metrics_project_resources
- storage_volume_nbd
- projects_restricted_storage_pool_access
- server_shutdown_action
- instances_placement_scriptlet_rebalance
api_status: stable
api_version: "1.0"
auth: trusted
public: false
auth_methods:
- tls
auth_user_name: x
auth_user_method: tls
environment:
addresses:
- 192.168.X.X:8443
- '[fd99:X:X::33]:8443'
- '[fd99:X:X:X:X:X:X:X]:8443'
- 10.245.X.X:8443
- '[fd42:X:X:X::1]:8443'
- 10.69.X.X:8443
- '[fd42:X:X:X::1]:8443'
- 10.124.X.X:8443
- '[fd42:X:X:X::1]:8443'
- 10.0.X.X:8443
- 10.0.X.X:8443
- 10.107.X.X:8443
- '[fd42:X:X:X::1]:8443'
architectures:
- x86_64
- i686
certificate: |
-----BEGIN CERTIFICATE-----
X
certificate_fingerprint: x
driver: qemu | lxc
driver_version: 11.0.0 | 7.0.0
firewall: nftables
kernel: Linux
kernel_architecture: x86_64
kernel_features: {}
kernel_version: 6.19.14-zabbly+
lxc_features: {}
os_name: Debian GNU/Linux
os_version: "13"
project: services
server: incus
server_clustered: false
server_event_mode: full-mesh
server_name: incus-server
server_pid: 3229
server_version: 7.0.0
storage: btrfs | lvm
storage_version: 6.14 | 2.03.31(2) (2025-02-27) / 1.02.205 (2025-02-27) / 4.50.0
storage_supported_drivers:
- name: btrfs
version: "6.14"
remote: false
- name: cephfs
version: 18.2.7
remote: true
- name: lvm
version: 2.03.31(2) (2025-02-27) / 1.02.205 (2025-02-27) / 4.50.0
remote: false
- name: truenas
version: 0.7.7
remote: true
- name: ceph
version: 18.2.7
remote: true
- name: cephobject
version: 18.2.7
remote: true
- name: dir
version: "1"
remote: false
AI Disclosure: This issue report was drafted with the assistance of an AI agent
(Claude) during an infrastructure debugging session. The root cause analysis, source
code line references, and reproduction script were produced by the agent and then
reviewed by a human operator. We respect the Incus project's position on AI tooling
and disclose this transparently. The reproduction script is provided as a diagnostic
aid — we are not submitting AI-generated code as a contribution or pull request.
Is there an existing issue for this?
Is this happening on an up to date version of Incus?
Current behavior
The new built-in S3 listener in Incus 7.0 is missing support for CopyObject. This causes a silent failure with a 0 byte file creation which may not be noticed by the user.
Manual reproduction (minimal curl):
Detailed info
Two bugs:
SerializationError: empty response payload.The bug is likely in the
handleObjectmethod ininternal/server/storage/s3/local/server.goat lines 203–215Line 209 dispatches all
PUTrequests toputObjectwithout inspecting thex-amz-copy-sourceheader. The S3 CopyObject API is defined as a PUT with that header set and an empty body.Expected behavior
Per the S3 CopyObject specification, a
PUTwithx-amz-copy-sourceshould:As incus version 6.23 had a working implementation I suggest we should maintain this compatibility. I ran into the issue using incus integrated S3 bucket to store state of pulumi incus terraform provider bridge, after update to 7.0 it breaks.
Steps to reproduce
Self-contained reproduction script is provided: reproduce-incus-s3-copyobject.sh
Incus system details