{"record":{"id":"f75d21abeaca8071","repo":"Budibase/budibase","slug":"project-package-is-missing-project-json","errorCode":null,"errorMessage":"Project package is missing project.json.","messagePattern":"Project package is missing project\\.json\\.","errorType":"validation","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/projects/backups/imports.ts","lineNumber":973,"sourceCode":"            PROJECT_DEPENDENCY_INDEX_FILE,\n            PROJECT_DOCS_DIRECTORY,\n          ].includes(entry)\n      )\n    ) {\n      throw new HTTPError(\"Project package contains unsupported files.\", 400)\n    }\n\n    const manifestPath = join(tmpPath, PROJECT_MANIFEST_FILE)\n    const projectPath = join(tmpPath, PROJECT_FILE)\n    const dependencyIndexPath = join(tmpPath, PROJECT_DEPENDENCY_INDEX_FILE)\n    const docsPath = join(tmpPath, PROJECT_DOCS_DIRECTORY)\n\n    await Promise.all([\n      fsp.access(manifestPath).catch(() => {\n        throw new HTTPError(\"Project package is missing manifest.json.\", 400)\n      }),\n      fsp.access(projectPath).catch(() => {\n        throw new HTTPError(\"Project package is missing project.json.\", 400)\n      }),\n      fsp.access(dependencyIndexPath).catch(() => {\n        throw new HTTPError(\n          \"Project package is missing dependency-index.json.\",\n          400\n        )\n      }),\n    ])\n\n    const [manifest, project, dependencyIndex] = await Promise.all([\n      readJsonFile<ProjectPackageManifest>(manifestPath),\n      readJsonFile<Project>(projectPath),\n      readJsonFile<ProjectPackageDependencyIndex>(dependencyIndexPath),\n    ])\n\n    validateManifest(manifest)\n    validateProject(project)\n    validateDependencyIndexShape(dependencyIndex)","sourceCodeStart":955,"sourceCodeEnd":991,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/projects/backups/imports.ts#L955-L991","documentation":"Project packages must contain a project.json file at the archive root alongside the manifest. extractProjectPackage() checks it with fsp.access in the Promise.all at imports.ts:966-982 and throws this HTTP 400 at imports.ts:972-974 when the file is missing. project.json holds the project definition, so its absence makes the package unimportable.","triggerScenarios":"Importing a package tarball whose root lacks project.json — fsp.access(projectPath) rejects and the catch converts it to this HTTP 400.","commonSituations":"Hand-editing or re-zipping an extracted package and deleting/renaming project.json; importing a docs-only or partial archive; truncated downloads that omitted entries; older exports with a different layout.","solutions":["Re-export the project package from the source workspace so project.json is included","Check the archive root contains project.json (tar -tf pkg.tgz | grep project.json)","If re-archiving manually, keep project.json at the archive root with its original name","Re-download the package in case the original transfer was corrupted"],"exampleFix":"null","handlingStrategy":"validation","validationCode":"import { createReadStream } from 'fs'\nimport { parse } from 'tar'\nconst hasProjectJson = await new Promise<boolean>((resolve, reject) => {\n  const ws = parse({ onReadEntry: (e: any) => { if (e.path === 'project.json') { resolve(true); ws.abort?.() } }, onEnd: () => resolve(false) })\n  createReadStream(packagePath).pipe(ws as any)\n  ws.on('error', reject)\n})\nif (!hasProjectJson) throw new Error('package is missing project.json at archive root')","typeGuard":"function isCompleteProjectPackage(entries: readonly string[]): boolean {\n  return ['manifest.json', 'project.json', 'dependency-index.json'].every(f => entries.includes(f))\n}","tryCatchPattern":"try {\n  await importProjectPackage(file)\n} catch (err) {\n  if (err instanceof HTTPError && err.status === 400 && err.message === 'Project package is missing project.json.') {\n    // re-export a complete package from the source workspace\n  } else {\n    throw err\n  }\n}","preventionTips":["Keep all exported files together; project.json is required, not optional","Verify archive root contents before import (tar -tf)","Re-download instead of reconstructing partially available files","Watch for tools that strip or rename JSON files during transfer"],"tags":["import","missing-file","http-400"],"backgroundTag":"missing-package-manifest","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}