diff --git a/autogpt_platform/frontend/next.config.mjs b/autogpt_platform/frontend/next.config.mjs index d4595990a2..e4e4cdf544 100644 --- a/autogpt_platform/frontend/next.config.mjs +++ b/autogpt_platform/frontend/next.config.mjs @@ -3,6 +3,14 @@ import { withSentryConfig } from "@sentry/nextjs"; /** @type {import('next').NextConfig} */ const nextConfig = { productionBrowserSourceMaps: true, + experimental: { + serverActions: { + bodySizeLimit: "256mb", + }, + // Increase body size limit for API routes (file uploads) - 256MB to match backend limit + proxyClientMaxBodySize: "256mb", + middlewareClientMaxBodySize: "256mb", + }, images: { domains: [ // We dont need to maintain alphabetical order here diff --git a/autogpt_platform/frontend/src/app/api/proxy/[...path]/route.ts b/autogpt_platform/frontend/src/app/api/proxy/[...path]/route.ts index 09235f9c3b..293c406373 100644 --- a/autogpt_platform/frontend/src/app/api/proxy/[...path]/route.ts +++ b/autogpt_platform/frontend/src/app/api/proxy/[...path]/route.ts @@ -6,6 +6,10 @@ import { import { environment } from "@/services/environment"; import { NextRequest, NextResponse } from "next/server"; +// Increase body size limit to 256MB to match backend file upload limit +export const maxDuration = 300; // 5 minutes timeout for large uploads +export const dynamic = "force-dynamic"; + function buildBackendUrl(path: string[], queryString: string): string { const backendPath = path.join("/"); return `${environment.getAGPTServerBaseUrl()}/${backendPath}${queryString}`; diff --git a/autogpt_platform/frontend/src/lib/autogpt-server-api/client.ts b/autogpt_platform/frontend/src/lib/autogpt-server-api/client.ts index 3b0666bf62..682fc14108 100644 --- a/autogpt_platform/frontend/src/lib/autogpt-server-api/client.ts +++ b/autogpt_platform/frontend/src/lib/autogpt-server-api/client.ts @@ -910,7 +910,37 @@ export default class BackendAPI { reject(new Error("Invalid JSON response")); } } else { - reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`)); + // Handle file size errors with user-friendly message + if (xhr.status === 413) { + reject(new Error("File is too large — max size is 256MB")); + return; + } + + // Try to parse error response for better messages + let errorMessage = `Upload failed (${xhr.status})`; + try { + const errorData = JSON.parse(xhr.responseText); + if (errorData.detail) { + if ( + typeof errorData.detail === "string" && + errorData.detail.includes("exceeds the maximum") + ) { + const match = errorData.detail.match( + /maximum allowed size of (\d+)MB/, + ); + const maxSize = match ? match[1] : "256"; + errorMessage = `File is too large — max size is ${maxSize}MB`; + } else if (typeof errorData.detail === "string") { + errorMessage = errorData.detail; + } + } else if (errorData.error) { + errorMessage = errorData.error; + } + } catch { + // Keep default message if parsing fails + } + + reject(new Error(errorMessage)); } }); diff --git a/autogpt_platform/frontend/src/lib/autogpt-server-api/helpers.ts b/autogpt_platform/frontend/src/lib/autogpt-server-api/helpers.ts index 7e20783042..4cb24df77d 100644 --- a/autogpt_platform/frontend/src/lib/autogpt-server-api/helpers.ts +++ b/autogpt_platform/frontend/src/lib/autogpt-server-api/helpers.ts @@ -184,6 +184,11 @@ export function serializeRequestBody( } export async function parseApiError(response: Response): Promise { + // Handle 413 Payload Too Large with user-friendly message + if (response.status === 413) { + return "File is too large — max size is 256MB"; + } + try { const errorData = await response.clone().json(); @@ -205,6 +210,16 @@ export async function parseApiError(response: Response): Promise { return response.statusText; // Fallback to status text if no message } + // Check for file size error from backend + if ( + typeof errorData.detail === "string" && + errorData.detail.includes("exceeds the maximum") + ) { + const match = errorData.detail.match(/maximum allowed size of (\d+)MB/); + const maxSize = match ? match[1] : "256"; + return `File is too large — max size is ${maxSize}MB`; + } + return errorData.detail || errorData.error || response.statusText; } catch { return response.statusText;