# Buggy code
def wrapper(self, *args, **kwargs):
    if self.rule.workflow.iocache.active:
        cache = getattr(self.rule.workflow.iocache, func.__name__)
        normalized = self.rstrip("/")
        if normalized in cache:
            return cache[normalized]
        v = func(self, *args, **kwargs)
        cache[normalized] = v
        return v
    else:
        return func(self, *args, **kwargs)


# Traceback (FileNotFoundError)
Building DAG of jobs...
Traceback (most recent call last):
File "<base_path>/software/miniconda/envs/snakemake/lib/python3.7/site-packages/snakemake/__init__.py", line 709, in snakemake
keepincomplete=keep_incomplete,
File "<base_path>/software/miniconda/envs/snakemake/lib/python3.7/site-packages/snakemake/workflow.py", line 670, in execute
dag.init()
File "<base_path>/software/miniconda/envs/snakemake/lib/python3.7/site-packages/snakemake/dag.py", line 177, in init
job = self.update(self.file2jobs(file), file=file, progress=progress)
File "<base_path>/software/miniconda/envs/snakemake/lib/python3.7/site-packages/snakemake/dag.py", line 715, in update
progress=progress,
File "<base_path>/software/miniconda/envs/snakemake/lib/python3.7/site-packages/snakemake/dag.py", line 792, in update_
file.inventory()
File "<base_path>/software/miniconda/envs/snakemake/lib/python3.7/site-packages/snakemake/io.py", line 210, in inventory
self._local_inventory(cache)
File "<base_path>/software/miniconda/envs/snakemake/lib/python3.7/site-packages/snakemake/io.py", line 224, in _local_inventory
with os.scandir(path) as scan:
FileNotFoundError: [Errno 2] No such file or directory: '<analysis_patch>/tmp_batch113/codons'

# Fixed code
def wrapper(self, *args, **kwargs):
    iocache = self.rule.workflow.iocache
    if not iocache.active or self.inventory_path is None:
        return func(self, *args, **kwargs)

    cache = getattr(iocache, func.__name__)
    # first check if file is present in cache
    if self.inventory_path in cache:
        res = cache[self.inventory_path]
    # check if the folder was cached
    elif iocache.in_inventory(self.inventory_root):
        # as the folder was cached, we do know that the file does not exist
        if raise_error:
            # make sure that the cache behaves the same as non-cached results
            raise FileNotFoundError("No such file or directory: {}".format(self.file))
        else:
            return False
    elif self._is_function:
        raise ValueError(
            "This IOFile is specified as a function and may not be used directly."
        )
    else:
        res = IOCACHE_DEFERRED

    if res is IOCACHE_DEFERRED:
        # determine values that are not yet cached
        self._add_to_inventory(func.__name__)
        res = cache[self.inventory_path]

    # makes sure that cache behaves same as non-cached results
    if res is IOCACHE_BROKENSYMLINK:
        raise WorkflowError("File {} seems to be a broken symlink.".format(self.file))
    elif res is IOCACHE_NOTEXIST:
        raise FileNotFoundError("File {} does not exist.".format(self.file))
    elif res is IOCACHE_NOPERMISSION:
        raise PermissionError(
            "File {} does not have the required permissions.".format(self.file)
        )
    return res