HumanSignal/label-studio · error · ValidationError
{storage.url_scheme}://{storage.bucket}/{storage.prefix} not
Error message
{storage.url_scheme}://{storage.bucket}/{storage.prefix} not found. What it means
The final except KeyError in S3StorageSerializerMixin.validate() surfaces the KeyError raised inside S3Storage.validate_connection() as ValidationError(f'{storage.url_scheme}://{storage.bucket}/{storage.prefix} not found.'). It reaches the API caller with the actual storage's scheme/bucket/prefix interpolated, meaning the bucket+prefix combination had no matching keys (see error 162).
Source
Thrown at label_studio/io_storages/s3/serializers.py:74
if (
e.response.get('Error').get('Code') in ['SignatureDoesNotMatch', '403']
or e.response.get('ResponseMetadata').get('HTTPStatusCode') == 403
):
raise ValidationError(
'Cannot connect to S3 {bucket_name} with specified AWS credentials'.format(
bucket_name=storage.bucket
)
)
if (
e.response.get('Error').get('Code') in ['NoSuchBucket', '404']
or e.response.get('ResponseMetadata').get('HTTPStatusCode') == 404
):
raise ValidationError('Cannot find bucket {bucket_name} in S3'.format(bucket_name=storage.bucket))
except TypeError as e:
logger.info(f'It seems access keys are incorrect: {e}', exc_info=True)
raise ValidationError('It seems access keys are incorrect')
except KeyError:
raise ValidationError(f'{storage.url_scheme}://{storage.bucket}/{storage.prefix} not found.')
return data
class S3ImportStorageSerializer(S3StorageSerializerMixin, ImportStorageSerializer):
type = StorageTypeField(default=os.path.basename(os.path.dirname(__file__)))
presign = serializers.BooleanField(required=False, default=True)
def validate_s3_endpoint(self, value):
if value and settings.SSRF_PROTECTION_ENABLED:
validate_url_for_ssrf(value, block_local_urls=True)
return value
class Meta:
model = S3ImportStorage
fields = '__all__'
class S3ExportStorageSerializer(S3StorageSerializerMixin, ExportStorageSerializer):View on GitHub (pinned to 0b49e9b539)
Solutions
- Upload at least one object under bucket/prefix before connecting the import storage.
- Correct or remove the `prefix` field so it matches where files actually live.
- Verify bucket/endpoint/region so listing hits the intended bucket.
Example fix
// before
{"bucket": "my-bucket", "prefix": "imports/"} // bucket has files at root
// after
{"bucket": "my-bucket", "prefix": ""} Defensive patterns
Strategy: validation
Validate before calling
import boto3
def prefix_keycount(bucket: str, prefix: str, **client_kwargs) -> int:
s3 = boto3.client('s3', **client_kwargs)
return s3.list_objects_v2(Bucket=bucket, Prefix=prefix, MaxKeys=1).get('KeyCount', 0)
if prefix_keycount('my-bucket', 'imports/') == 0:
raise ValueError('No objects under bucket/prefix; fix prefix or upload data first') Type guard
def prefix_matches_layout(storage: dict) -> bool:
p = storage.get('prefix', '')
return p == '' or bool(storage.get('bucket')) Try / catch
try:
serializer.is_valid(raise_exception=True)
except ValidationError as e:
msg = str(e.detail)
if 'not found' in msg and '://' in msg:
# KeyError from validate_connection: bucket/prefix had zero keys
print(f'No objects at {msg}; adjust prefix or upload files') Prevention
- Dry-run ListObjectsV2 with the exact bucket/prefix before creating the storage.
- Automate an upload-then-connect ordering in pipelines (data must exist first).
- Standardize prefix conventions (trailing slash) across environments.
- Use a health-check script that lists each configured storage prefix on deploy.
When it happens
Trigger: Any import-storage create/update where validate_connection()'s ListObjectsV2 returns KeyCount 0/None for the given bucket and prefix, triggering the KeyError that this handler converts.
Common situations: Same as prefix-not-found: empty bucket, wrong prefix, objects at root while a prefix is set, endpoint/region mismatch returning empty result sets.
Related errors
- Cannot find bucket {bucket_name} in S3
- {self.url_scheme}://{self.bucket}/{self.prefix} not found.
- exc.kwargs['report']
- Wrong credentials for S3 {bucket_name}
- It seems access keys are incorrect
AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29).
Data as JSON: /api/errors/5d80e0754a3471f6.
Report an issue: GitHub.