diff --git a/autogpt_platform/backend/backend/api/features/workspace/routes.py b/autogpt_platform/backend/backend/api/features/workspace/routes.py index 2102b1f102..b96e953491 100644 --- a/autogpt_platform/backend/backend/api/features/workspace/routes.py +++ b/autogpt_platform/backend/backend/api/features/workspace/routes.py @@ -273,13 +273,16 @@ async def upload_file( f"Failed to soft-delete over-quota file {workspace_file.id} " f"in workspace {workspace.id}: {e}" ) + from backend.util.workspace import _format_bytes + raise fastapi.HTTPException( status_code=413, - detail={ - "message": "Storage limit exceeded (concurrent upload)", - "used_bytes": new_total, - "limit_bytes": storage_limit_bytes, - }, + detail=( + f"Storage limit exceeded. " + f"You've used {_format_bytes(new_total)} of your " + f"{_format_bytes(storage_limit_bytes)} quota. " + f"Delete some files or upgrade your plan for more storage." + ), ) return UploadFileResponse( diff --git a/autogpt_platform/backend/backend/util/workspace.py b/autogpt_platform/backend/backend/util/workspace.py index a57469baa0..0cefe770e4 100644 --- a/autogpt_platform/backend/backend/util/workspace.py +++ b/autogpt_platform/backend/backend/util/workspace.py @@ -20,6 +20,17 @@ from backend.util.settings import Config from backend.util.virus_scanner import scan_content_safe from backend.util.workspace_storage import compute_file_checksum, get_workspace_storage + +def _format_bytes(n: int) -> str: + """Format bytes as a human-readable string (e.g. 250 MB, 1.0 GB).""" + if n < 1024: + return f"{n} B" + if n < 1024 * 1024: + return f"{n / 1024:.0f} KB" + if n < 1024 * 1024 * 1024: + return f"{n / (1024 * 1024):.0f} MB" + return f"{n / (1024 * 1024 * 1024):.1f} GB" + logger = logging.getLogger(__name__) @@ -211,10 +222,11 @@ class WorkspaceManager: projected_usage = current_usage + len(content) if storage_limit > 0 and projected_usage > storage_limit: - used_pct = (current_usage / storage_limit) * 100 raise ValueError( - f"Storage limit exceeded: {current_usage:,} bytes used " - f"of {storage_limit:,} bytes ({used_pct:.1f}%)" + f"Storage limit exceeded. " + f"You've used {_format_bytes(current_usage)} of your " + f"{_format_bytes(storage_limit)} quota. " + f"Delete some files or upgrade your plan for more storage." ) if storage_limit > 0 and projected_usage / storage_limit >= 0.8: logger.warning( diff --git a/autogpt_platform/frontend/src/lib/direct-upload.ts b/autogpt_platform/frontend/src/lib/direct-upload.ts index 22fd79f4a4..c6050fc84a 100644 --- a/autogpt_platform/frontend/src/lib/direct-upload.ts +++ b/autogpt_platform/frontend/src/lib/direct-upload.ts @@ -40,8 +40,18 @@ export async function uploadFileDirect( }); if (!res.ok) { - const detail = await res.text().catch(() => res.statusText); - throw new Error(`Upload failed (${res.status}): ${detail}`); + let message: string; + try { + const body = await res.json(); + // Backend returns { detail: "..." } or { detail: { message: "..." } } + message = + typeof body.detail === "string" + ? body.detail + : (body.detail?.message ?? res.statusText); + } catch { + message = res.statusText; + } + throw new Error(message); } return res.json();