{"record":{"id":"f82e3bddfa975d62","repo":"langflow-ai/langflow","slug":"fs-path-cannot-be-empty","errorCode":null,"errorMessage":"fs_path cannot be empty","messagePattern":"fs_path cannot be empty","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/flows_helpers.py","lineNumber":59,"sourceCode":"from langflow.services.deps import get_settings_service\nfrom langflow.services.storage.service import StorageService\n\nif TYPE_CHECKING:\n    from langflow.services.database.models.user.model import User\n\n\ndef _get_safe_flow_path(fs_path: str, user_id: UUID, storage_service: StorageService) -> Path:\n    \"\"\"Get a safe filesystem path for flow storage, restricted to user's flows directory.\n\n    Allows both absolute and relative paths, but ensures they're within the user's flows directory.\n\n    Uses ``os.path.realpath`` + ``startswith`` for containment — the sanitiser pattern\n    recognised by CodeQL's ``py/path-injection`` analysis. ``realpath`` canonicalises\n    the path and follows symlinks, so the returned path is safe to pass to filesystem\n    operations.\n    \"\"\"\n    if not fs_path:\n        raise HTTPException(status_code=400, detail=\"fs_path cannot be empty\")\n\n    # Normalize path separators first (before security checks to prevent backslash bypass)\n    normalized_path = fs_path.replace(\"\\\\\", \"/\")\n\n    # Reject directory traversal and null bytes (check normalized path)\n    if \"..\" in normalized_path:\n        raise HTTPException(\n            status_code=400,\n            detail=\"Invalid fs_path: directory traversal (..) is not allowed\",\n        )\n    if \"\\x00\" in normalized_path:\n        raise HTTPException(\n            status_code=400,\n            detail=\"Invalid fs_path: null bytes are not allowed\",\n        )\n\n    # Build and canonicalise the safe base directory path.\n    base_dir = storage_service.data_dir / \"flows\" / str(user_id)","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/flows_helpers.py#L41-L77","documentation":"HTTP 400 from _get_safe_flow_path: the fs_path value passed on flow create/update was falsy (empty string or whitespace-only handled as empty) before any path resolution is attempted. _get_safe_flow_path is the single sanitiser through which every flow fs_path must pass, so an empty value is rejected up front rather than resolving to the user's flows root.","triggerScenarios":"POST/PATCH /api/v1/flows with body {\"fs_path\": \"\"} (or the string arriving empty after client-side templating), causing _verify_fs_path -> _get_safe_flow_path to hit the `if not fs_path` guard.","commonSituations":"Client code interpolates fs_path from a variable that is undefined/empty (\"flows/{id}.json\" template with missing id); a form field submitted blank; JSON where fs_path is \"\" instead of being omitted or set to null.","solutions":["Omit the fs_path key entirely, or send null — None is explicitly allowed and means DB-only storage.","Set fs_path to a real relative filename, e.g. \"my_flow.json\"; it is resolved under <data_dir>/flows/<user_id>/.","Fix the client-side template/variable that produced the empty string."],"exampleFix":"// before\n{\"name\": \"My Flow\", \"fs_path\": \"\"}\n// after\n{\"name\": \"My Flow\", \"fs_path\": \"my_flow.json\"}","handlingStrategy":"validation","validationCode":"if (!fsPath || !fsPath.trim()) throw new Error('fs_path must be a non-empty filename');","typeGuard":"const isValidFsPath = (p: unknown): p is string => typeof p === 'string' && p.trim().length > 0;","tryCatchPattern":null,"preventionTips":["Omit optional fs_path instead of sending \"\"","Never template fs_path from possibly-undefined variables"],"tags":["validation","fs-path","http-400","flows"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}