lobehub/lobehub · error · TRPCError
BAD_REQUEST
BAD_REQUEST
Error message
File size cannot be negative
What it means
Thrown by file.createFile (file.ts:238) when actualSize is negative after the metadata-fetch fallback. actualSize starts as input.size and is only overridden by the URL's Content-Length when that value is >= 1; therefore a negative actualSize means input.size was negative (the schema does not bound it below zero) OR a misconfigured server returned a negative Content-Length that the >= 1 guard would actually NOT adopt — so in practice this is a client passing a negative size. businessFileUploadCheck is called first (for telemetry/abuse signal) then the BAD_REQUEST is thrown.
Solutions
- On the client, compute size from the actual File/Blob (.size) and guard `if (size < 0) throw` before calling the RPC.
- If the size is genuinely unknown, pass 0 (the server will then prefer the URL's Content-Length when >= 1) rather than a negative sentinel.
- Validate the upload schema with .nonnegative() on size at the zod layer in the client.
Example fix
// before
await trpc.file.createFile.mutate({ ..., size: -1 /* unknown */ });
// after
const size = file?.size ?? 0;
if (size < 0) throw new Error('computed file size is negative');
await trpc.file.createFile.mutate({ ..., size }); Defensive patterns
Strategy: validation
Validate before calling
const size = file?.size ?? 0;
if (!Number.isFinite(size) || size < 0) {
throw new Error('computed file size is invalid');
}
await trpc.file.createFile.mutate({ ..., size }); Type guard
function isNonNegativeSize(n: unknown): n is number {
return typeof n === 'number' && Number.isFinite(n) && n >= 0;
} Prevention
- Compute size from File/Blob.size; never use a negative sentinel for 'unknown'.
- Validate the upload schema with z.number().nonnegative() on the client.
- If size is unknown, pass 0 so the server prefers the URL's Content-Length when >= 1.
When it happens
Trigger: Client calling file.createFile with input.size < 0 (e.g. a signed-int overflow, a default -1 'unknown size' sentinel, or a bug computing size from a failed stat). The metadata-fetch step does not rescue it because Content-Length only overrides when >= 1.
Common situations: Client using -1 to mean 'size unknown' instead of omitting the field; integer underflow when subtracting offsets; size derived from a failed HEAD request that left a NaN/negative in a downstream calculation.
Understand the failure class
Background: BAD_REQUEST error code: request rejected as invalid (HTTP 400) - causes and fixes across libraries — this error's family across 8 libraries.
Related errors
AI-assisted analysis of lobehub/lobehub@10f24d7ade (2026-08-12).
Data as JSON: /api/errors/29484729d8d26183.
Report an issue: GitHub.
Appendix: source
Thrown at apps/server/src/routers/lambda/file.ts:238
try {
const { contentLength } = await ctx.fileService.getFileMetadata(input.url);
if (contentLength >= 1) {
actualSize = contentLength;
}
} catch {
// If metadata fetch fails, use original size from input
}
if (actualSize < 0) {
await businessFileUploadCheck({
actualSize,
clientIp: ctx.clientIp ?? undefined,
inputSize: input.size,
url: input.url,
userId: ctx.userId,
workspaceId: ctx.workspaceId,
});
throw new TRPCError({ code: 'BAD_REQUEST', message: 'File size cannot be negative' });
}
const { id } = await ctx.serverDB.transaction(async (trx) => {
await businessFileUploadCheck({
actualSize,
clientIp: ctx.clientIp ?? undefined,
inputSize: input.size,
transaction: trx,
url: input.url,
userId: ctx.userId,
workspaceId: ctx.workspaceId,
});
let shouldRefreshGlobalFile = false;
if (isExist && existingFile.url && existingFile.url !== input.url) {
shouldRefreshGlobalFile = !(await isStoredObjectAvailable(
ctx.fileService,
existingFile.url,View on GitHub (pinned to 10f24d7ade)