{"record":{"id":"29484729d8d26183","repo":"lobehub/lobehub","slug":"bad-request-294847","errorCode":"BAD_REQUEST","errorMessage":"File size cannot be negative","messagePattern":"File size cannot be negative","errorType":"exception","errorClass":"TRPCError","httpStatus":400,"severity":"error","filePath":"apps/server/src/routers/lambda/file.ts","lineNumber":238,"sourceCode":"      try {\n        const { contentLength } = await ctx.fileService.getFileMetadata(input.url);\n        if (contentLength >= 1) {\n          actualSize = contentLength;\n        }\n      } catch {\n        // If metadata fetch fails, use original size from input\n      }\n\n      if (actualSize < 0) {\n        await businessFileUploadCheck({\n          actualSize,\n          clientIp: ctx.clientIp ?? undefined,\n          inputSize: input.size,\n          url: input.url,\n          userId: ctx.userId,\n          workspaceId: ctx.workspaceId,\n        });\n        throw new TRPCError({ code: 'BAD_REQUEST', message: 'File size cannot be negative' });\n      }\n\n      const { id } = await ctx.serverDB.transaction(async (trx) => {\n        await businessFileUploadCheck({\n          actualSize,\n          clientIp: ctx.clientIp ?? undefined,\n          inputSize: input.size,\n          transaction: trx,\n          url: input.url,\n          userId: ctx.userId,\n          workspaceId: ctx.workspaceId,\n        });\n\n        let shouldRefreshGlobalFile = false;\n        if (isExist && existingFile.url && existingFile.url !== input.url) {\n          shouldRefreshGlobalFile = !(await isStoredObjectAvailable(\n            ctx.fileService,\n            existingFile.url,","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/lobehub/lobehub/blob/10f24d7ade75139093a9373b364f6bc91f3cd7db/apps/server/src/routers/lambda/file.ts#L220-L256","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait trpc.file.createFile.mutate({ ..., size: -1 /* unknown */ });\n// after\nconst size = file?.size ?? 0;\nif (size < 0) throw new Error('computed file size is negative');\nawait trpc.file.createFile.mutate({ ..., size });","handlingStrategy":"validation","validationCode":"const size = file?.size ?? 0;\nif (!Number.isFinite(size) || size < 0) {\n  throw new Error('computed file size is invalid');\n}\nawait trpc.file.createFile.mutate({ ..., size });","typeGuard":"function isNonNegativeSize(n: unknown): n is number {\n  return typeof n === 'number' && Number.isFinite(n) && n >= 0;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["trpc","file","validation","upload","client-bug"],"backgroundTag":null,"analyzedSha":"10f24d7ade75139093a9373b364f6bc91f3cd7db","analyzedAt":"2026-08-12T11:43:19.543Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}