HumanSignal/label-studio · error · ValidationError

{underlying connection validation error}

Error message

{underlying connection validation error}

What it means

After permission checks, ExportStorageListAPI.perform_create instantiates the storage model and calls validate_connection(); any exception (auth failure, missing container, network error) is re-raised as a DRF ValidationError wrapping the underlying message. It exists because export storage serializers skip connection validation, so the view performs an explicit check with the credentials from request.data.

Source

Thrown at label_studio/io_storages/api.py:107

        # check failed jobs and sync their statuses
        StorageClass.ensure_storage_statuses(storages)
        return storages

    def perform_create(self, serializer):
        from rest_framework.exceptions import PermissionDenied

        project = serializer.validated_data.get('project')
        if project is not None and not project.has_permission(self.request.user):
            raise PermissionDenied('You do not have permission to create storages for this project.')

        # double check: not export storages don't validate connection in serializer,
        # just make another explicit check here, note: in this create API we have credentials in request.data
        instance = serializer.Meta.model(**serializer.validated_data)
        try:
            instance.validate_connection()
        except Exception as exc:
            raise ValidationError(exc)

        storage = serializer.save()
        if settings.SYNC_ON_TARGET_STORAGE_CREATION:
            storage.sync()


class ExportStorageDetailAPI(generics.RetrieveUpdateDestroyAPIView):
    """RUD storage by pk specified in URL"""

    permission_required = ViewClassPermission(
        GET=all_permissions.storages_view,
        PATCH=all_permissions.storages_change,
        PUT=all_permissions.storages_change,
        DELETE=all_permissions.storages_change,
    )
    parser_classes = (JSONParser, FormParser, MultiPartParser)
    serializer_class = ExportStorageSerializer

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Read the wrapped message in the response detail — it names the real cloud error
  2. Test the same credentials with the cloud CLI (aws s3 ls / gsutil ls / az storage container list)
  3. Fix the credential fields (access key, secret, container/bucket name, prefix) and retry
  4. Ensure network egress to the provider endpoint and correct region/endpoint URL
  5. Grant the IAM identity permissions to list the target container

Example fix

// before
{"bucket": "my-bucket", "aws_access_key_id": "AKIA...", "aws_secret_access_key": "<old-rotated-key>"}  // 400 SignatureDoesNotMatch
// after
{"bucket": "my-bucket", "aws_access_key_id": "AKIA...", "aws_secret_access_key": "<current-key>"}  // 201
Defensive patterns

Strategy: try-catch

Validate before calling

# pre-validate credentials with the cloud CLI before POSTing
import subprocess
subprocess.run(["aws", "s3", "ls", f"s3://{bucket}"], check=True)

Type guard

def storage_payload_has_credentials(p):
    return bool(p.get("aws_access_key_id") and p.get("aws_secret_access_key") and p.get("bucket"))

Try / catch

try:
    resp = requests.post(export_storage_url, json=payload, headers=headers)
    resp.raise_for_status()
except requests.HTTPError as e:
    detail = resp.json().get("detail", "")  # wrapped validate_connection error
    logging.error("Storage connection failed: %s", detail)

Prevention

When it happens

Trigger: POST creating an export storage whose credentials are wrong (bad access key, missing account name/key, nonexistent container, expired token), causing validate_connection() to throw.

Common situations: Typo'd AWS secret, rotated cloud credentials not yet updated in Label Studio, storage target bucket deleted or renamed, VPC/firewall blocking outbound calls to the cloud provider, IAM policy lacking list/get on the bucket.

Related errors


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