{"record":{"id":"78dde92c1c4bb04d","repo":"agentscope-ai/agentscope","slug":"malformed-s3-blob-uri-uri-r","errorCode":null,"errorMessage":"Malformed S3 blob URI: {uri!r}","messagePattern":"Malformed S3 blob URI: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/agentscope/app/rag/blob_store/_s3.py","lineNumber":183,"sourceCode":"            \"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 \"\n                f\"configured bucket {expected_bucket!r}.\",\n            )\n        return key\n","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/app/rag/blob_store/_s3.py#L165-L201","documentation":"After the s3:// scheme check, _parse_uri requires both a non-empty bucket and a non-empty key: 's3://' alone, 's3://bucket' (no key), or 's3:///key' (no bucket) raise ValueError('Malformed S3 blob URI'). This catches truncated or template-interpolated URIs where a component came out empty.","triggerScenarios":"Passing 's3://my-bucket' (missing /key), 's3:///k' (empty bucket), or URIs built with an unset env/config variable, e.g. f\"s3://{bucket}/{key}\" with bucket=None rendering as 's3://None/k' variants or empty strings.","commonSituations":"Config-driven URI construction where BUCKET_NAME env var is unset in one environment; templating bugs dropping the key; string-concatenated URIs missing a slash producing 's3://bucketkey'.","solutions":["Log/inspect the exact URI at the call site to spot the empty component","Set and validate required config (bucket name, key prefix) before building URIs","Prefer write_stream(key) which builds the URI for you and returns a correct one","Add a startup assertion: assert bucket and key when constructing URIs manually"],"exampleFix":"# before\nuri = f\"s3://{os.environ.get('BUCKET')}/{key}\"  # BUCKET unset -> malformed\nawait s3store.open(uri)\n\n# after\nbucket = os.environ['BUCKET']  # fails fast if missing\nawait s3store.open(f\"s3://{bucket}/{key}\")","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\n\ndef valid_s3_uri(uri: str) -> bool:\n    if not uri.startswith('s3://'):\n        return False\n    parts = uri[5:].split('/', 1)\n    return len(parts) == 2 and all(parts)\n\nassert valid_s3_uri(uri), f'malformed S3 URI: {uri!r}'","typeGuard":"from urllib.parse import urlparse\n\ndef parse_s3_uri(uri: str) -> tuple[str, str] | None:\n    if not uri.startswith('s3://'):\n        return None\n    bucket, _, key = uri[5:].partition('/')\n    return (bucket, key) if bucket and key else None","tryCatchPattern":"try:\n    await store.open(uri)\nexcept ValueError as e:\n    if 'Malformed S3 blob URI' in str(e):\n        ...  # log uri, fix bucket/key construction\n    raise","preventionTips":["Fail fast on empty config values (bucket env vars) before building URIs","Validate URIs with a parse helper before storage/DB round-trips","Prefer write_stream(key) which constructs well-formed URIs for you"],"tags":["s3","blob-store","uri-parsing","validation"],"backgroundTag":"malformed-uri","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}