different-ai/openwork · error · ApiError
file_too_large
file_too_large
Error message
Direct uploads support files up to ${DIRECT_UPLOAD_MAX_BYTES} bytes. What it means
After resolving the file inside an authorized root, resolveAuthorizedFile stats it and enforces the DIRECT_UPLOAD_MAX_BYTES limit; files over the limit (and 0-byte files) get a 413 file_too_large ApiError.
Source
Thrown at apps/server/src/extensions/cloud-uploads.ts:134
for (const root of roots) {
try {
pushUniqueResolvedPath(realRoots, await realpath(root));
} catch (error) {
if (!isRecord(error) || error.code !== "ENOENT") throw error;
}
}
const candidates = isAbsolute(requested)
? [resolve(requested)]
: searchRoots(config, context, roots).map((root) => resolve(root, requested));
for (const candidate of candidates) {
if (!roots.some((root) => isWithinRoot(candidate, root))) continue;
try {
const realCandidate = await realpath(candidate);
if (!realRoots.some((root) => isWithinRoot(realCandidate, root))) continue;
const info = await stat(realCandidate);
if (!info.isFile()) continue;
if (info.size < 1 || info.size > DIRECT_UPLOAD_MAX_BYTES) {
throw new ApiError(413, "file_too_large", `Direct uploads support files up to ${DIRECT_UPLOAD_MAX_BYTES} bytes.`, {
size: info.size,
maxBytes: DIRECT_UPLOAD_MAX_BYTES,
});
}
return realCandidate;
} catch (error) {
if (isRecord(error) && error.code === "ENOENT") continue;
throw error;
}
}
throw new ApiError(404, "file_not_found", "File was not found inside an authorized workspace root.", { path: requested });
}
function mimeTypeForPath(path: string) {
const lower = path.toLowerCase();
if (lower.endsWith(".pdf")) return "application/pdf";
if (lower.endsWith(".docx")) return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
if (lower.endsWith(".xlsx")) return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";View on GitHub (pinned to 2b7df46e8a)
Solutions
- Upload the file through the chunked/regular upload path instead of direct upload
- Compress or split the file so it fits under DIRECT_UPLOAD_MAX_BYTES
- Check the file isn't unexpectedly empty (size < 1 also triggers this) before uploading
- Host the file externally and reference by URL if it's genuinely too large
Example fix
// before await uploadDirect(largeVideoPath); // 500MB // after await uploadChunked(largeVideoPath); // chunked path has its own limits
Defensive patterns
Strategy: validation
Validate before calling
if (file.size > DIRECT_UPLOAD_MAX_BYTES) return useChunkedUpload(file);
Try / catch
try { await uploadDirect(p); } catch (e) { if (e.code === "file_too_large") { await uploadChunked(p); } else throw e; } Prevention
- Compare size against the server-advertised max before upload
- Auto-fallback to chunked upload
- Skip 0-byte files at selection
When it happens
Trigger: Direct-uploading a file whose stat size exceeds DIRECT_UPLOAD_MAX_BYTES, or an empty (0-byte) file, which is also rejected by the size < 1 check.
Common situations: Uploading large PDFs/videos/datasets via the direct upload path; symlinks resolving to big files; empty placeholder files created by scripts.
Related errors
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/f03e19e6687fd90b.
Report an issue: GitHub.