HumanSignal/label-studio · error · ValidationError

exc.kwargs['report']

Error message

exc.kwargs['report']

What it means

S3StorageSerializerMixin.validate_bucket() runs boto3's validate_bucket_name on the submitted bucket. If the value fails boto3's client-side parameter validation, a botocore ParamValidationError carrying a human-readable `report` is converted into a DRF ValidationError with that report text. It fires before any network call.

Source

Thrown at label_studio/io_storages/s3/serializers.py:33

logger = logging.getLogger(__name__)


class S3StorageSerializerMixin:
    secure_fields = ['aws_access_key_id', 'aws_secret_access_key']

    def to_representation(self, instance):
        result = super().to_representation(instance)
        for attr in self.secure_fields:
            result.pop(attr)
        return result

    def validate_bucket(self, value):
        if not value:
            return value
        try:
            validate_bucket_name({'Bucket': value})
        except ParamValidationError as exc:
            raise ValidationError(exc.kwargs['report']) from exc
        return value

    def validate(self, data):
        data = super().validate(data)
        if not data.get('bucket', None):
            return data

        storage = self.instance
        if storage:
            for key, value in data.items():
                setattr(storage, key, value)
        else:
            if 'id' in self.initial_data:
                storage_object = self.Meta.model.objects.get(id=self.initial_data['id'])
                for attr in self.secure_fields:
                    data[attr] = data.get(attr) or getattr(storage_object, attr)
            storage = self.Meta.model(**data)
        try:

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Send only the bare bucket name (3–63 chars, lowercase letters, numbers, dots/hyphens) in the `bucket` field.
  2. Strip any s3:// scheme or path from the value before submitting.
  3. Pre-validate the name with botocore's validate_bucket_name in your client code.

Example fix

// before
{"bucket": "s3://My_Bucket/data"}

// after
{"bucket": "my-bucket"}
Defensive patterns

Strategy: validation

Validate before calling

import re

BUCKET_RE = re.compile(r'^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$')

def valid_bucket_name(name: str) -> bool:
    return bool(name) and bool(BUCKET_RE.match(name)) and '..' not in name

if not valid_bucket_name(payload['bucket']):
    raise ValueError('bucket must be 3-63 chars, lowercase letters/numbers/dots/hyphens')

Type guard

def is_bare_bucket_name(value: str) -> bool:
    return isinstance(value, str) and not value.startswith('s3://') and '/' not in value

Try / catch

try:
    serializer.is_valid(raise_exception=True)
except ValidationError as e:
    # e.detail carries the botocore report; fix the bucket field accordingly
    logger.warning('Bucket name rejected: %s', e.detail)

Prevention

When it happens

Trigger: Submitting an S3 storage create/update request whose `bucket` field violates S3 naming rules (empty after strip, uppercase, invalid characters, too long, leading/trailing dots/dashes).

Common situations: Pasting a full s3://bucket/path URL into the bucket field; bucket names with underscores or uppercase from older setups; accidental whitespace; env-substitution leaving a placeholder like ${BUCKET}.

Related errors


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/d80fb08d3e83ba98. Report an issue: GitHub.