{"record":{"id":"2998f6c44b03e8cc","repo":"Budibase/budibase","slug":"project-package-is-too-large","errorCode":null,"errorMessage":"Project package is too large.","messagePattern":"Project package is too large\\.","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/projects/backups/imports.ts","lineNumber":210,"sourceCode":"        400\n      )\n    }\n    if (entry.isSymbolicLink()) {\n      throw new HTTPError(\"Project package contains unsupported links.\", 400)\n    }\n    if (entry.isDirectory()) {\n      files.push(\n        ...(await readDirectoryRecursively(fullPath, rootPath, totals))\n      )\n    } else {\n      const stats = await fsp.stat(fullPath)\n      totals.files += 1\n      totals.bytes += stats.size\n      if (totals.files > MAX_PACKAGE_FILES) {\n        throw new HTTPError(\"Project package contains too many files.\", 400)\n      }\n      if (totals.bytes > MAX_EXTRACTED_SIZE_BYTES) {\n        throw new HTTPError(\"Project package is too large.\", 400)\n      }\n      files.push(fullPath)\n    }\n  }\n\n  return files\n}\n\nconst validateProjectPackageBeforeExtraction = async (file: {\n  path: string\n}) => {\n  const archiveHeader = new Uint8Array(2)\n  const archiveFile = await fsp.open(file.path, \"r\")\n  try {\n    await archiveFile.read(archiveHeader, 0, archiveHeader.length, 0)\n  } finally {\n    await archiveFile.close()\n  }","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/projects/backups/imports.ts#L192-L228","documentation":"readDirectoryRecursively walks the extracted project package directory and accumulates total file count and byte size. When the cumulative extracted size exceeds MAX_EXTRACTED_SIZE_BYTES it throws this HTTPError (400). Budibase enforces this limit to prevent resource exhaustion (zip bombs / oversized imports) on the server.","triggerScenarios":"Importing a project package (backup upload) whose extracted contents total more bytes than MAX_EXTRACTED_SIZE_BYTES, as measured while recursively reading the extraction directory after an earlier file pushed the running total over the limit.","commonSituations":"Restoring a very large app export; a package that balloons on extraction (compressed tar.gz much smaller than extracted contents, i.e. compression-bomb style packages); accidental inclusion of build artifacts, node_modules or large attachments inside the export directory.","solutions":["Reduce the package size: remove unnecessary files (node_modules, build output, attachments) from the export directory before compressing.","Check MAX_EXTRACTED_SIZE_BYTES in packages/server/src/sdk/workspace/projects/backups/imports.ts and, if you self-host and accept the risk, raise the limit via configuration.","Verify the uploaded .tar.gz is not corrupted/duplicated content by re-exporting the project from source.","Split very large projects into smaller apps, or import subsets of resources manually."],"exampleFix":"// before: exporting everything including heavy artifacts\ntar -czf app-export.tar.gz ./my-app  // my-app contains node_modules, dist\n// after: export only the app resources\ntar -czf app-export.tar.gz --exclude=node_modules --exclude=dist ./my-app","handlingStrategy":"validation","validationCode":"import { statSync, readdirSync } from \"fs\"\nimport { join } from \"path\"\n\nfunction dirSize(dir: string): { files: number; bytes: number } {\n  let totals = { files: 0, bytes: 0 }\n  for (const entry of readdirSync(dir, { withFileTypes: true })) {\n    const p = join(dir, entry.name)\n    if (entry.isDirectory()) {\n      const sub = dirSize(p)\n      totals.files += sub.files\n      totals.bytes += sub.bytes\n    } else {\n      totals.files += 1\n      totals.bytes += statSync(p).size\n    }\n  }\n  return totals\n}\n\nconst t = dirSize(extractedDir)\nif (t.bytes > MAX_EXTRACTED_SIZE_BYTES) throw new Error(\"Package too large\")","typeGuard":null,"tryCatchPattern":"try {\n  await api.importProjectPackage(file)\n} catch (err) {\n  if (err?.status === 400 && err?.message === \"Project package is too large.\") {\n    // surface size guidance to user: reduce package contents or raise limit\n  } else throw err\n}","preventionTips":["Measure extracted size before upload with `du -sb` and compare against the server limit","Exclude node_modules, build output and attachments from export directories","Watch for compression bombs: small .tar.gz can extract to huge sizes — always check extracted size, not archive size","Prefer splitting oversized projects into multiple apps"],"tags":["http-400","import","file-size-limit","backup-restore"],"backgroundTag":"package-size-limit-exceeded","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}