Handle oversize upload errors cleanly
This commit is contained in:
parent
334dcd1edf
commit
e0025b4cbf
3 changed files with 47 additions and 2 deletions
|
|
@ -1568,10 +1568,21 @@ async function startRun(): Promise<void> {
|
|||
setStage("idle", "Waiting for input", "Pick a file first. The machine is not clairvoyant.");
|
||||
return;
|
||||
}
|
||||
const runtimeConfig = state.runtimeConfig;
|
||||
const uploadLimit = runtimeConfig?.limits.maxUploadBytes;
|
||||
if (uploadLimit !== undefined && state.file.size > uploadLimit) {
|
||||
setJobState("failed");
|
||||
setStage(
|
||||
"failed",
|
||||
"File too large",
|
||||
`${state.file.name} is ${formatByteLimit(state.file.size)}. Hosted uploads are capped at ${formatByteLimit(uploadLimit)}.`,
|
||||
);
|
||||
addLog("Failure", "Selected file is over the hosted upload limit.");
|
||||
return;
|
||||
}
|
||||
resetRunArtifacts({ preserveSourceImage: true });
|
||||
renderEventLog();
|
||||
runButton.disabled = true;
|
||||
const runtimeConfig = state.runtimeConfig;
|
||||
const maxSteps = runtimeConfig?.limits.maxSteps ?? 48;
|
||||
const defaultSteps = runtimeConfig?.limits.defaultSteps ?? 48;
|
||||
state.solverStepBudget = Math.max(0, Math.min(maxSteps, parseOptionalInteger(stepsInput) ?? defaultSteps));
|
||||
|
|
@ -1604,6 +1615,21 @@ async function startRun(): Promise<void> {
|
|||
}
|
||||
|
||||
async function acceptFile(file: File): Promise<void> {
|
||||
const uploadLimit = state.runtimeConfig?.limits.maxUploadBytes;
|
||||
if (uploadLimit !== undefined && file.size > uploadLimit) {
|
||||
state.file = null;
|
||||
resetRunArtifacts();
|
||||
dropzoneLabel.textContent = "Choose image";
|
||||
setJobState("failed");
|
||||
setStage(
|
||||
"failed",
|
||||
"File too large",
|
||||
`${file.name} is ${formatByteLimit(file.size)}. Hosted uploads are capped at ${formatByteLimit(uploadLimit)}.`,
|
||||
);
|
||||
addLog("Failure", "Selected file is over the hosted upload limit.");
|
||||
await renderEverything();
|
||||
return;
|
||||
}
|
||||
state.file = file;
|
||||
resetRunArtifacts();
|
||||
dropzoneLabel.textContent = file.name;
|
||||
|
|
|
|||
|
|
@ -1282,10 +1282,17 @@ async function startRun() {
|
|||
setStage("idle", "Waiting for input", "Pick a file first. The machine is not clairvoyant.");
|
||||
return;
|
||||
}
|
||||
const runtimeConfig = state.runtimeConfig;
|
||||
const uploadLimit = runtimeConfig?.limits.maxUploadBytes;
|
||||
if (uploadLimit !== undefined && state.file.size > uploadLimit) {
|
||||
setJobState("failed");
|
||||
setStage("failed", "File too large", `${state.file.name} is ${formatByteLimit(state.file.size)}. Hosted uploads are capped at ${formatByteLimit(uploadLimit)}.`);
|
||||
addLog("Failure", "Selected file is over the hosted upload limit.");
|
||||
return;
|
||||
}
|
||||
resetRunArtifacts({ preserveSourceImage: true });
|
||||
renderEventLog();
|
||||
runButton.disabled = true;
|
||||
const runtimeConfig = state.runtimeConfig;
|
||||
const maxSteps = runtimeConfig?.limits.maxSteps ?? 48;
|
||||
const defaultSteps = runtimeConfig?.limits.defaultSteps ?? 48;
|
||||
state.solverStepBudget = Math.max(0, Math.min(maxSteps, parseOptionalInteger(stepsInput) ?? defaultSteps));
|
||||
|
|
@ -1318,6 +1325,17 @@ async function startRun() {
|
|||
}
|
||||
}
|
||||
async function acceptFile(file) {
|
||||
const uploadLimit = state.runtimeConfig?.limits.maxUploadBytes;
|
||||
if (uploadLimit !== undefined && file.size > uploadLimit) {
|
||||
state.file = null;
|
||||
resetRunArtifacts();
|
||||
dropzoneLabel.textContent = "Choose image";
|
||||
setJobState("failed");
|
||||
setStage("failed", "File too large", `${file.name} is ${formatByteLimit(file.size)}. Hosted uploads are capped at ${formatByteLimit(uploadLimit)}.`);
|
||||
addLog("Failure", "Selected file is over the hosted upload limit.");
|
||||
await renderEverything();
|
||||
return;
|
||||
}
|
||||
state.file = file;
|
||||
resetRunArtifacts();
|
||||
dropzoneLabel.textContent = file.name;
|
||||
|
|
|
|||
|
|
@ -26,3 +26,4 @@
|
|||
{"ts": "2026-04-29T17:20:00+00:00", "type": "implementation", "status": "ok", "note": "Removed the hosted solver loss chart because the explicit solver's loss-like diagnostic is not a useful live objective; solver status now surfaces step, signal, grid alignment, and displacement terms instead."}
|
||||
{"ts": "2026-04-29T17:29:40+00:00", "type": "implementation", "status": "ok", "note": "Hosted GUI now emits explicit service logs for queue saturation, job queue/start/completion/failure/cancel events, and wait/run/total seconds so load pressure shows up in journald instead of only in transient SSE state."}
|
||||
{"ts": "2026-04-29T21:40:11+00:00", "type": "implementation", "status": "ok", "note": "Fixed GUI failed-response handling so submit/config/queue/cancel errors read the Response body once, preserving the real server error instead of throwing 'body stream already read'."}
|
||||
{"ts": "2026-04-29T21:42:58+00:00", "type": "implementation", "status": "ok", "note": "Oversize uploads were hitting nginx 413 before FastAPI and the GUI masked the response with a double-read error; GUI now preflights file size and reads failed responses once so users see the actual upload limit."}
|
||||
|
|
|
|||
Loading…
Reference in a new issue