{"record":{"id":"d072f0a812b72340","repo":"apache/beam","slug":"tried-to-list-nonexistent-s3-path-s3-s-s-fake-client","errorCode":null,"errorMessage":"Tried to list nonexistent S3 path: s3://%s/%s","messagePattern":"Tried to list nonexistent S3 path: s3://(.+?)/(.+?)","errorType":"http","errorClass":"S3ClientError","httpStatus":404,"severity":"error","filePath":"sdks/python/apache_beam/io/aws/clients/s3/fake_client.py","lineNumber":106,"sourceCode":"    \"\"\"\n    # TODO: Do we want to mock out a lack of credentials?\n    file_ = self.get_file(request.bucket, request.object)\n    return file_.get_metadata()\n\n  def list(self, request):\n    bucket = request.bucket\n    prefix = request.prefix or ''\n    matching_files = []\n\n    for file_bucket, file_name in sorted(iter(self.files)):\n      if bucket == file_bucket and file_name.startswith(prefix):\n        file_object = self.get_file(file_bucket, file_name).get_metadata()\n        matching_files.append(file_object)\n\n    if not matching_files:\n      message = 'Tried to list nonexistent S3 path: s3://%s/%s' % (\n          bucket, prefix)\n      raise messages.S3ClientError(message, 404)\n\n    # Handle pagination.\n    items_per_page = 5\n    if not request.continuation_token:\n      range_start = 0\n    else:\n      if request.continuation_token not in self.list_continuation_tokens:\n        raise ValueError('Invalid page token.')\n      range_start = self.list_continuation_tokens[request.continuation_token]\n      del self.list_continuation_tokens[request.continuation_token]\n\n    result = messages.ListResponse(\n        items=matching_files[range_start:range_start + items_per_page])\n\n    if range_start + items_per_page < len(matching_files):\n      next_range_start = range_start + items_per_page\n      next_continuation_token = '_page_token_%s_%s_%d' % (\n          bucket, prefix, next_range_start)","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/aws/clients/s3/fake_client.py#L88-L124","documentation":"FakeS3Client.list raises S3ClientError with 'Tried to list nonexistent S3 path: s3://bucket/prefix' (404) when no fake file under the bucket matches the requested prefix. It mimics a nonexistent-prefix listing failure, which real S3 would return as an empty list instead.","triggerScenarios":"Calling list() with a bucket/prefix combination where no fake files were created whose keys start with that prefix, so matching_files ends up empty.","commonSituations":"Unit tests listing a prefix before seeding files; prefix strings with typos or missing/extra trailing slashes; bucket name mismatch between fixture seeding and the code under test.","solutions":["Create fake files under the prefix before calling list","Compare the prefix string carefully (trailing slash, case) against seeded keys","Ensure the bucket matches the one used in create_file calls","If empty results are valid in real S3, handle S3ClientError 404 or use a different fake setup"],"exampleFix":"// before\nresults = fake_client.list(messages.ListRequest('mybucket', 'results/'))\n// after\nfake_client.create_file('mybucket', 'results/part-0000', b'a')\nresults = fake_client.list(messages.ListRequest('mybucket', 'results/'))","handlingStrategy":"validation","validationCode":"seeded = [k for (_, k) in fake_client.files if _ == bucket and k.startswith(prefix)]\nassert seeded, f'no fake files under s3://{bucket}/{prefix}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Create at least one fake file under the exact prefix before listing","Normalize prefixes (trailing slash) in a helper used by both seeding and listing","Use the same bucket-name constant everywhere in the test","Remember the fake raises on empty results, unlike real S3"],"tags":["aws","s3","test-fixture","io"],"backgroundTag":"resource-not-found","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}