langflow-ai/langflow · error · HTTPException
Failed to write flow to filesystem: {e}
Error message
Failed to write flow to filesystem: {e} What it means
HTTP 500 from _save_flow_to_fs: an OSError occurred while writing the flow JSON to the validated filesystem path (mkdir of parents, aiofiles.open for write, or the write itself). The original HTTPExceptions from path validation are re-raised untouched; this branch is purely I/O failure after validation passed, and the exception is logged with the flow name and path via logger.aexception.
Source
Thrown at src/backend/base/langflow/api/v1/flows_helpers.py:195
if not await safe_path.exists():
await safe_path.touch()
async def _save_flow_to_fs(flow: Flow, user_id: UUID, storage_service: StorageService) -> None:
"""Save flow data to the filesystem at the validated path."""
if not flow.fs_path:
return
try:
safe_path = _get_safe_flow_path(flow.fs_path, user_id, storage_service)
await safe_path.parent.mkdir(parents=True, exist_ok=True)
async with aiofiles.open(str(safe_path), "w") as f:
await f.write(flow.model_dump_json())
except HTTPException:
raise
except OSError as e:
await logger.aexception("Failed to write flow %s to path %s", flow.name, flow.fs_path)
raise HTTPException(status_code=500, detail=f"Failed to write flow to filesystem: {e}") from e
async def _deduplicate_flow_name(session: AsyncSession, name: str, user_id: UUID) -> str:
"""Return a unique flow name for *user_id*, appending ``(N)`` if needed."""
if not (await session.exec(select(Flow).where(Flow.name == name).where(Flow.user_id == user_id))).first():
return name
flows = (
await session.exec(
select(Flow).where(Flow.name.like(f"{name} (%")).where(Flow.user_id == user_id) # type: ignore[attr-defined]
)
).all()
# Extract copy-number suffixes: "MyFlow (2)" → 2
extract_number = re.compile(rf"^{re.escape(name)} \((\d+)\)$")
numbers = [int(m.group(1)) for f in flows if (m := extract_number.search(f.name))]
return f"{name} ({max(numbers) + 1})" if numbers else f"{name} (1)"View on GitHub (pinned to 976ec789d2)
Solutions
- Check disk space (df -h) and permissions on <data_dir>/flows/<user_id> for the backend user.
- In containers, ensure the mounted volume is writable by the container user (chown/chmod or runAsUser match).
- Remove any directory that collides with the target filename.
- Read the server log: the aexception line names the flow and fs_path that failed.
Example fix
# before: read-only volume docker run -v /srv/flows:/data/flows:ro ... # after docker run -v /srv/flows:/data/flows:rw ...
Defensive patterns
Strategy: fallback
Validate before calling
# pre-flight on the server
import os; d = f"{DATA_DIR}/flows/{user_id}"; assert os.access(d, os.W_OK), 'flows dir not writable' Try / catch
try { await saveFlow(body) } catch (e) { if (e.status === 500 && 'filesystem' in e.detail) { alertOpsDisk(); body = {...body, fs_path: null}; return await saveFlow(body); } throw e; } Prevention
- Monitor disk space and volume writability in containers
- Ensure uid/gid match on mounted volumes
- Read the aexception log line for flow name and path
When it happens
Trigger: Flow create/update with a valid fs_path where the server cannot write: disk full, permission denied on <data_dir>/flows/<user_id>, directory replaced by a read-only mount, or the file is a directory at that name.
Common situations: Docker container where the data volume is read-only or owned by a different uid; disk exhaustion; SELinux/AppArmor denying writes; an existing directory named exactly like the target .json file.
Related errors
- Multiple files are not allowed
- An error occurred while preparing the flow.
- Cannot create .components directory: {exc.strerror or exc}
- Invalid base directory: {e}
- Invalid path: {e}
AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14).
Data as JSON: /api/errors/9a16edaa2e6ca73a.
Report an issue: GitHub.