{"record":{"id":"82f08f7f320128ab","repo":"HumanSignal/label-studio","slug":"wrong-credentials-for-s3-bucket-name","errorCode":null,"errorMessage":"Wrong credentials for S3 {bucket_name}","messagePattern":"Wrong credentials for S3 (.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/io_storages/s3/serializers.py","lineNumber":54,"sourceCode":"    def validate(self, data):\n        data = super().validate(data)\n        if not data.get('bucket', None):\n            return data\n\n        storage = self.instance\n        if storage:\n            for key, value in data.items():\n                setattr(storage, key, value)\n        else:\n            if 'id' in self.initial_data:\n                storage_object = self.Meta.model.objects.get(id=self.initial_data['id'])\n                for attr in self.secure_fields:\n                    data[attr] = data.get(attr) or getattr(storage_object, attr)\n            storage = self.Meta.model(**data)\n        try:\n            storage.validate_connection()\n        except ParamValidationError:\n            raise ValidationError('Wrong credentials for S3 {bucket_name}'.format(bucket_name=storage.bucket))\n        except ClientError as e:\n            if (\n                e.response.get('Error').get('Code') in ['SignatureDoesNotMatch', '403']\n                or e.response.get('ResponseMetadata').get('HTTPStatusCode') == 403\n            ):\n                raise ValidationError(\n                    'Cannot connect to S3 {bucket_name} with specified AWS credentials'.format(\n                        bucket_name=storage.bucket\n                    )\n                )\n            if (\n                e.response.get('Error').get('Code') in ['NoSuchBucket', '404']\n                or e.response.get('ResponseMetadata').get('HTTPStatusCode') == 404\n            ):\n                raise ValidationError('Cannot find bucket {bucket_name} in S3'.format(bucket_name=storage.bucket))\n        except TypeError as e:\n            logger.info(f'It seems access keys are incorrect: {e}', exc_info=True)\n            raise ValidationError('It seems access keys are incorrect')","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/io_storages/s3/serializers.py#L36-L72","documentation":"In S3StorageSerializerMixin.validate(), after building the storage object, validate_connection() is called; if it raises a botocore ParamValidationError the serializer raises ValidationError('Wrong credentials for S3 {bucket_name}'). Note the message is a plain .format() on a literal not containing braces placement for the value, so the rendered text keeps the literal '{bucket_name}'. It signals malformed/insufficient AWS parameters rather than an auth rejection from AWS.","triggerScenarios":"storage.validate_connection() raising ParamValidationError during serializer validation — e.g. missing or wrong-typed aws_access_key_id/aws_secret_access_key/region/bucket parameters, often because secure_mode merges undefined attrs into None.","commonSituations":"Empty AWS keys in env (None passed to boto3 client); secure_mode storage update omitting credential fields so they resolve to None; region unset so client construction fails validation; expired/rotated keys removed from settings.","solutions":["Provide valid AWS credentials (aws_access_key_id / aws_secret_access_key / security_token) or rely on a correctly configured instance role.","If using secure_mode updates, ensure stored secure fields actually exist on the existing storage_object.","Set the correct region_name so the boto3 client can be constructed.","Check the server log for the underlying ParamValidationError report for the exact bad parameter."],"exampleFix":"// before\n{\"bucket\": \"my-bucket\", \"aws_access_key_id\": \"\", \"aws_secret_access_key\": null}\n\n// after\n{\"bucket\": \"my-bucket\", \"aws_access_key_id\": \"AKIA...\", \"aws_secret_access_key\": \"secret\", \"region_name\": \"us-east-1\"}","handlingStrategy":"validation","validationCode":"import os\n\ndef aws_credentials_present() -> bool:\n    return all([\n        os.environ.get('AWS_ACCESS_KEY_ID'),\n        os.environ.get('AWS_SECRET_ACCESS_KEY'),\n        os.environ.get('AWS_REGION') or os.environ.get('AWS_DEFAULT_REGION'),\n    ])\n\nif not aws_credentials_present():\n    raise ValueError('Set AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_REGION first')","typeGuard":"def has_credential_fields(data: dict) -> bool:\n    keys = ('aws_access_key_id', 'aws_secret_access_key', 'region_name')\n    return any(isinstance(data.get(k), str) and data[k] for k in keys)","tryCatchPattern":"try:\n    serializer.is_valid(raise_exception=True)\nexcept ValidationError as e:\n    if 'Wrong credentials for S3' in str(e.detail):\n        # underlying ParamValidationError: check which AWS param was None/invalid\n        logger.warning('S3 param validation failed for %s; check keys/region', bucket)","preventionTips":["Never submit empty-string or null AWS credential fields; omit them to use instance roles.","In secure_mode, confirm the existing storage actually stores the secure fields you rely on.","Always set region_name with custom credentials.","Rotate keys in sync — update Label Studio storage when AWS keys change."],"tags":["s3","aws","credentials","serializer","validation"],"backgroundTag":"invalid-aws-credentials","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}