lllyasviel/Fooocus · error · Exception

**** ERROR: Saving image outside the output folder is not al

Error message

**** ERROR: Saving image outside the output folder is not allowed.

What it means

save_image's timestamped-filename helper (ldm_patched/utils/path_utils.py) refuses to write outside the designated output folder: it joins output_dir with the subfolder taken from filename_prefix and verifies via os.path.commonpath that the resolved path is still inside output_dir. If filename_prefix contains '..' segments (or an absolute-path trick) that escapes, it prints a diagnostic and raises a bare Exception. This is a path-traversal guard for image saving.

Source

Thrown at ldm_patched/utils/path_utils.py:253

    def compute_vars(input, image_width, image_height):
        input = input.replace("%width%", str(image_width))
        input = input.replace("%height%", str(image_height))
        return input

    filename_prefix = compute_vars(filename_prefix, image_width, image_height)

    subfolder = os.path.dirname(os.path.normpath(filename_prefix))
    filename = os.path.basename(os.path.normpath(filename_prefix))

    full_output_folder = os.path.join(output_dir, subfolder)

    if os.path.commonpath((output_dir, os.path.abspath(full_output_folder))) != output_dir:
        err = "**** ERROR: Saving image outside the output folder is not allowed." + \
              "\n full_output_folder: " + os.path.abspath(full_output_folder) + \
              "\n         output_dir: " + output_dir + \
              "\n         commonpath: " + os.path.commonpath((output_dir, os.path.abspath(full_output_folder))) 
        print(err)
        raise Exception(err)

    try:
        counter = max(filter(lambda a: a[1][:-1] == filename and a[1][-1] == "_", map(map_filename, os.listdir(full_output_folder))))[0] + 1
    except ValueError:
        counter = 1
    except FileNotFoundError:
        os.makedirs(full_output_folder, exist_ok=True)
        counter = 1
    return full_output_folder, filename, counter, subfolder, filename_prefix

View on GitHub (pinned to ae05379cc9)

Solutions

  1. Strip traversal segments from the prefix: keep only os.path.basename components, or normalize and reject '..' before calling save_image.
  2. Pass a plain filename (e.g. 'Fooocus/img_001') and let the function build the subfolder under output_dir.
  3. Read the printed diagnostic (it shows full_output_folder vs output_dir vs commonpath) to see exactly which prefix component escaped.

Example fix

# before
save_image(images, output_dir, '../../shared/img', ...)
# after
prefix = os.path.basename('../../shared/img')  # -> 'img'
save_image(images, output_dir, prefix, ...)
Defensive patterns

Strategy: validation

Validate before calling

import os
safe = not os.path.isabs(filename_prefix) and '..' not in os.path.normpath(filename_prefix).split(os.sep)
if not safe:
    filename_prefix = os.path.basename(filename_prefix)
# strongest guarantee: resolved target must stay under output_dir
target = os.path.abspath(os.path.join(output_dir, os.path.dirname(os.path.normpath(filename_prefix))))
assert os.path.commonpath((output_dir, target)) == output_dir

Type guard

def is_safe_prefix(output_dir: str, prefix: str) -> bool:
    p = os.path.normpath(prefix)
    if os.path.isabs(p) or p.startswith('..'):
        return False
    target = os.path.abspath(os.path.join(output_dir, p))
    return os.path.commonpath((output_dir, target)) == output_dir

Try / catch

try:
    save_image(img, output_dir, prefix, ...)
except Exception as e:
    if 'outside the output folder' in str(e):
        prefix = os.path.basename(prefix)  # retry with sanitized prefix
        save_image(img, output_dir, prefix, ...)
    else:
        raise

Prevention

When it happens

Trigger: Passing filename_prefix like '../foo/img', '/etc/passwd/img', or a subfolder that normalizes above output_dir; also triggered when output_dir is a relative path and the prefix resolves to a sibling directory.

Common situations: Automating Fooocus via its API with a caller-supplied filename_prefix; using wildcard/path templates that include '..' on Windows (where path joining differs); symlinked output folders that break the commonpath comparison.

Related errors


AI-assisted analysis of lllyasviel/Fooocus@ae05379cc9 (2026-08-15). Data as JSON: /api/errors/c29b5bbf1268ae91. Report an issue: GitHub.