langflow-ai/langflow · warning · HTTPException

Folder must be one of: {', '.join(sorted(allowed_folders))}

Error message

Folder must be one of: {', '.join(sorted(allowed_folders))}

What it means

HTTP 400 from GET /files/profile_pictures/{folder_name}/{file_name} when folder_name is not in the allow-list computed by _get_allowed_profile_picture_folders(settings_service) — the set of folder names derived from the config dir's profile_pictures/ tree plus the package's bundled profile_pictures directories. The message enumerates the sorted allowed names so the caller can self-correct.

Source

Thrown at src/backend/base/langflow/api/v1/files.py:210

        raise HTTPException(status_code=500, detail=str(e)) from e


@router.get("/profile_pictures/{folder_name}/{file_name}")
async def download_profile_picture(
    folder_name: ValidatedFolderName,
    file_name: ValidatedFileName,
    settings_service: Annotated[SettingsService, Depends(get_settings_service)],
):
    """Download profile picture from local filesystem.

    Profile pictures are first looked up in config_dir/profile_pictures/,
    then fallback to the package's bundled profile_pictures directory.
    """
    try:
        # Only allow specific folder names (dynamic from config + package)
        allowed_folders = _get_allowed_profile_picture_folders(settings_service)
        if folder_name not in allowed_folders:
            raise HTTPException(status_code=400, detail=f"Folder must be one of: {', '.join(sorted(allowed_folders))}")

        # SECURITY: Extract only the final path component to prevent path traversal.
        # This is defense-in-depth on top of ValidatedFileName/ValidatedFolderName.
        safe_folder = Path(folder_name).name
        safe_file = Path(file_name).name

        extension = safe_file.split(".")[-1]
        config_dir = settings_service.settings.config_dir

        # SECURITY: use os.path.realpath + startswith — the sanitiser pattern
        # recognised by CodeQL's py/path-injection analysis. realpath canonicalises
        # the path and resolves symlinks, so the subsequent startswith check is
        # robust against both traversal sequences and symlink-based escapes.
        # os.path.join is deliberate here (PTH118) to match CodeQL's sanitiser model.
        allowed_base = os.path.realpath(os.path.join(str(config_dir), "profile_pictures"))  # noqa: PTH118
        candidate = os.path.realpath(os.path.join(allowed_base, safe_folder, safe_file))  # noqa: PTH118
        if candidate != allowed_base and not candidate.startswith(allowed_base + os.sep):
            raise HTTPException(status_code=404, detail="Profile picture not found")

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Use one of the folder names listed verbatim in the error detail
  2. Create the folder under <config_dir>/profile_pictures/ with at least one image so it enters the allow-list
  3. Check case-sensitivity — the comparison is exact

Example fix

# before
GET /files/profile_pictures/Avatars/avatar_1.png  # 400

# after
mkdir -p ~/.langflow/profile_pictures/Avatars  # add image
cp avatar_1.png ~/.langflow/profile_pictures/Avatars/
GET /files/profile_pictures/Avatars/avatar_1.png
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED_FOLDERS = {"defaults", "custom"}  # sync with server config

def folder_allowed(folder_name: str, allowed: set[str]) -> bool:
    return folder_name in allowed

Type guard

function isAllowedProfileFolder(folder: string, allowed: string[]): boolean {
  return allowed.includes(folder);
}

Try / catch

try:
    client.get(f"/files/profile_pictures/{folder}/{name}").raise_for_status()
except HTTPError as e:
    if e.response.status_code == 400:
        allowed = parse_allowed_folders(e.response.text)
        client.get(f"/files/profile_pictures/{pick(allowed)}/{name}")

Prevention

When it happens

Trigger: GET /files/profile_pictures/{unknown}/{file} with a folder not present under config_dir/profile_pictures/ or the bundled set; typos in folder names ('spaces' vs 'space', case sensitivity); requesting a folder that exists on one deployment but not another.

Common situations: Custom profile picture sets added to a different instance; renaming theme folders; frontend hardcoding a folder name that the deployment never provisioned.

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/5638729a2d87c0ad. Report an issue: GitHub.