mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
fix(platform): human-readable storage quota error messages
Backend: Replace raw byte counts ("262,144,000 bytes") with formatted
sizes ("250 MB of your 1 GB quota") and include upgrade guidance.
Frontend: Parse 413 JSON response in direct-upload.ts to extract the
human-readable detail message instead of dumping raw JSON to the user.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user