{"record":{"id":"44859da9fba86094","repo":"apache/beam","slug":"enoent","errorCode":"ENOENT","errorMessage":"Not found: %s","messagePattern":"Not found: (.+?)","errorType":"exception","errorClass":"IOError","httpStatus":404,"severity":"error","filePath":"sdks/python/apache_beam/io/aws/s3io.py","lineNumber":562,"sourceCode":"\n\nclass S3Downloader(Downloader):\n  def __init__(self, client, path, buffer_size):\n    self._client = client\n    self._path = path\n    self._bucket, self._name = parse_s3_path(path)\n    self._buffer_size = buffer_size\n\n    # Get object state.\n    self._get_request = (\n        messages.GetRequest(bucket=self._bucket, object=self._name))\n\n    try:\n      metadata = self._get_object_metadata(self._get_request)\n\n    except messages.S3ClientError as e:\n      if e.code == 404:\n        raise IOError(errno.ENOENT, 'Not found: %s' % self._path)\n      else:\n        logging.error('HTTP error while requesting file %s: %s', self._path, 3)\n        raise\n\n    self._size = metadata.size\n\n  @retry.with_exponential_backoff(\n      retry_filter=retry.retry_on_server_errors_and_timeout_filter)\n  def _get_object_metadata(self, get_request):\n    return self._client.get_object_metadata(get_request)\n\n  @property\n  def size(self):\n    return self._size\n\n  def get_range(self, start, end):\n    return self._client.get_range(self._get_request, start, end)\n","sourceCodeStart":544,"sourceCodeEnd":580,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/aws/s3io.py#L544-L580","documentation":"S3Downloader.__init__ fetches the object's metadata (HEAD request) when opening an S3 object for reading. If S3 returns HTTP 404, it translates this into IOError(errno.ENOENT, 'Not found: <path>'), the Python idiom for a missing file.","triggerScenarios":"Opening a nonexistent or already-deleted key via S3IO.open('s3://bucket/missing', 'r'); a read path constructed from a typo or from a listing that has since changed; wrong bucket/region so the key does not resolve.","commonSituations":"Race with a deletion job between listing and reading; wrong bucket name or AWS credentials scoped to another account; case-sensitivity mistakes in keys (S3 keys are case-sensitive).","solutions":["Verify the key exists (aws s3 ls s3://bucket/key or client.head_object) before opening.","Check the bucket name, region and key spelling/case.","Catch the IOError and handle ENOENT explicitly where absence is expected.","Confirm credentials grant s3:GetObject / s3:ListBucket (hidden 404s can result from permission filtering)."],"exampleFix":"// before\nwith s3io.open('s3://%s/%s' % (bucket, key)) as f: ...\n// after\nif not io.exists(path):\n    return None\ntry:\n    with io.open(path) as f: ...\nexcept IOError as e:\n    if e.errno != errno.ENOENT: raise","handlingStrategy":"try-catch","validationCode":"def s3_key_exists(io, path):\n    try:\n        return len(io.list_files(path)) > 0\n    except Exception:\n        return False","typeGuard":"def is_missing_file(exc):\n    return isinstance(exc, IOError) and exc.errno == errno.ENOENT","tryCatchPattern":"try:\n    with io.open(path) as f:\n        data = f.read()\nexcept IOError as e:\n    if e.errno == errno.ENOENT:\n        data = None  # handle absence\n    else:\n        raise","preventionTips":["Check existence before open when absence is a normal case.","Validate bucket/region/key spelling and case.","Watch for list-then-read races with deletion jobs."],"tags":["python","aws","s3","file-not-found","io"],"backgroundTag":"file-not-found","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}