{"record":{"id":"1cc958b91cb63ed3","repo":"agentscope-ai/agentscope","slug":"not-an-s3-blob-uri-uri-r","errorCode":null,"errorMessage":"Not an S3 blob URI: {uri!r}","messagePattern":"Not an S3 blob URI: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/agentscope/app/rag/blob_store/_s3.py","lineNumber":179,"sourceCode":"                \"S3BlobStore is not entered; use it inside \"\n                \"``async with`` before calling blob methods.\",\n            )\n        return self._session.client(\n            \"s3\",\n            region_name=self._region_name,\n            endpoint_url=self._endpoint_url,\n            aws_access_key_id=self._aws_access_key_id,\n            aws_secret_access_key=self._aws_secret_access_key,\n            aws_session_token=self._session_token,\n            use_ssl=self._use_ssl,\n            config=self._config,\n        )\n\n    @staticmethod\n    def _parse_uri(uri: str) -> tuple[str, str]:\n        \"\"\"Split an ``s3://{bucket}/{key}`` URI into ``(bucket, key)``.\"\"\"\n        if not uri.startswith(_SCHEME):\n            raise ValueError(f\"Not an S3 blob URI: {uri!r}\")\n        rest = uri[len(_SCHEME) :]\n        bucket, _, key = rest.partition(\"/\")\n        if not bucket or not key:\n            raise ValueError(f\"Malformed S3 blob URI: {uri!r}\")\n        return bucket, key\n\n    @classmethod\n    def _key_from_uri(cls, uri: str, expected_bucket: str) -> str:\n        \"\"\"Return the object key, asserting the bucket matches.\n\n        Used by mutating operations (``delete``, ``exists``) where\n        crossing into another bucket would be a bug — the configured\n        bucket is the only place the store owns objects.\n        \"\"\"\n        bucket, key = cls._parse_uri(uri)\n        if bucket != expected_bucket:\n            raise ValueError(\n                f\"Bucket {bucket!r} in URI {uri!r} does not match \"","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/app/rag/blob_store/_s3.py#L161-L197","documentation":"S3BlobStore._parse_uri splits s3://{bucket}/{key} URIs and rejects anything not starting with the s3:// scheme. It backs _key_from_uri and open, so passing a local:// URI, a bare key, or a plain path to an S3 store's URI-taking methods raises this ValueError immediately.","triggerScenarios":"Calling s3store.open('local://data/x'), s3store.exists('mykey'), or similar on S3BlobStore; also switching a configured backend from LocalBlobStore to S3BlobStore while keeping local:// URIs in the database.","commonSituations":"Mixed deployments (local dev with LocalBlobStore, prod with S3) where persisted blob URIs from one environment leak into the other; refactoring the blob backend behind a config flag without migrating stored URIs.","solutions":["Route by scheme: check uri.startswith('s3://') before handing it to S3BlobStore","Store URIs returned by write_stream and pass them back untouched","When migrating backends, copy/re-upload blobs and rewrite stored URIs","For bare keys, construct f's3://{bucket}/{key}' or use write_stream with the key directly"],"exampleFix":"# before\nasync with s3store as s:\n    await s.open('local://data/x')  # ValueError: Not an S3 blob URI\n\n# after\nasync with s3store as s:\n    await s.open('s3://my-bucket/data/x')","handlingStrategy":"validation","validationCode":"def is_s3_uri(uri: str) -> bool:\n    return uri.startswith('s3://')\n\nif not is_s3_uri(uri):\n    raise ValueError(f'refusing non-S3 URI for S3BlobStore: {uri!r}')\nawait store.open(uri)","typeGuard":"def is_s3_uri(uri: str) -> bool:\n    return uri.startswith('s3://')","tryCatchPattern":"try:\n    await store.open(uri)\nexcept ValueError as e:\n    if 'Not an S3 blob URI' in str(e):\n        ...  # route uri to the correct backend by scheme\n    raise","preventionTips":["Dispatch blob operations by URI scheme before picking a store","Persist write_stream's returned URI and pass it back verbatim","During backend migrations, rewrite stored URIs to match the active backend"],"tags":["s3","blob-store","uri-scheme"],"backgroundTag":"invalid-uri-scheme","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}