{"record":{"id":"0e7a52b2a5b54499","repo":"cocoindex-io/cocoindex","slug":"key-must-be-provided-when-bucket-name-or-uri-is-no","errorCode":null,"errorMessage":"key must be provided when bucket_name_or_uri is not an S3 URI.","messagePattern":"key must be provided when bucket_name_or_uri is not an S3 URI\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/amazon_s3/_source.py","lineNumber":227,"sourceCode":"            f = await amazon_s3.get_object(client, \"s3://my-bucket/data/config.json\")\n            data = await f.read()\n\n            # Via bucket name + key:\n            f = await amazon_s3.get_object(client, \"my-bucket\", \"data/config.json\")\n            data = await f.read()\n    \"\"\"\n    if bucket_name_or_uri.startswith(\"s3://\"):\n        if key is not None:\n            raise ValueError(\n                \"Cannot specify both an S3 URI and a separate key. \"\n                \"Pass either get_object(client, 's3://bucket/key') \"\n                \"or get_object(client, 'bucket', 'key').\"\n            )\n        bucket_name, key = _parse_s3_uri(bucket_name_or_uri)\n    else:\n        bucket_name = bucket_name_or_uri\n        if key is None:\n            raise ValueError(\n                \"key must be provided when bucket_name_or_uri is not an S3 URI.\"\n            )\n    return await _s3file_from_head(client, bucket_name, key)\n\n\nasync def read(client: AioBaseClient, uri: str, size: int = -1) -> bytes:\n    \"\"\"\n    Read object content directly from an S3 URI.\n\n    This is a convenience shortcut that skips the metadata fetch\n    (``head_object``) performed by :func:`get_object`.\n\n    Args:\n        client: An aiobotocore S3 client.\n        uri: An S3 URI (``s3://bucket/key``).\n        size: Number of bytes to read. If -1 (default), read the entire object.\n\n    Returns:","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/amazon_s3/_source.py#L209-L245","documentation":"When the first argument to get_object is not an s3:// URI it is treated as a bare bucket name, so a separate key is mandatory. If key is None in that branch, the function cannot know which object to fetch and raises this ValueError.","triggerScenarios":"Calling get_object(client, 'my-bucket') with no key, or get_object(client, 'my-bucket', key=None) where the first argument lacks the s3:// prefix.","commonSituations":"Forgetting the key when switching from URI form to bucket form; key computed dynamically (e.g. from a template) and evaluating to None due to an upstream bug.","solutions":["Pass the key: get_object(client, 'my-bucket', 'data/config.json').","Or use the full URI form: get_object(client, 's3://my-bucket/data/config.json').","Guard dynamic key values: raise early in your own code if key is None before calling get_object."],"exampleFix":"// before\nf = await amazon_s3.get_object(client, \"my-bucket\")\n\n// after\nf = await amazon_s3.get_object(client, \"my-bucket\", \"data/config.json\")","handlingStrategy":"validation","validationCode":"assert key is not None, \"key required when passing a bare bucket name\"\nf = await amazon_s3.get_object(client, bucket, key)","typeGuard":null,"tryCatchPattern":"try:\n    f = await amazon_s3.get_object(client, bucket, key)\nexcept ValueError as e:\n    logger.error(\"missing key for bucket %s: %s\", bucket, e)\n    raise","preventionTips":["Default key to an empty string or explicit value where your flow requires it.","Prefer the s3:// URI form so bucket+key travel together.","Fail fast on None keys at the call-site boundary."],"tags":["python","s3","arguments","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}