{"record":{"id":"bb8b611fd7b0a466","repo":"Budibase/budibase","slug":"project-package-could-not-be-decrypted","errorCode":null,"errorMessage":"Project package could not be decrypted.","messagePattern":"Project package could not be decrypted\\.","errorType":"validation","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/projects/backups/imports.ts","lineNumber":931,"sourceCode":"  file: { path: string },\n  encryptPassword?: string\n): Promise<ExtractedProjectPackage> {\n  const fileStats = await fsp.stat(file.path)\n  if (fileStats.size > MAX_ARCHIVE_SIZE_BYTES) {\n    throw new HTTPError(\"Project package is too large.\", 400)\n  }\n  if (encryptPassword && encryptPassword.length > MAX_ENCRYPT_PASSWORD_LENGTH) {\n    throw new HTTPError(\"Project package password is too long.\", 400)\n  }\n\n  await validateProjectPackageBeforeExtraction(file)\n  const tmpPath = await untarFile(file)\n  try {\n    if (encryptPassword) {\n      try {\n        await decryptFiles(tmpPath, encryptPassword)\n      } catch {\n        throw new HTTPError(\"Project package could not be decrypted.\", 400)\n      }\n    }\n\n    const packageFiles = await readDirectoryRecursively(tmpPath)\n    const rootEntries = await fsp.readdir(tmpPath)\n    if (rootEntries.some(entry => entry.endsWith(\".enc\")) && !encryptPassword) {\n      throw new HTTPError(\n        \"Files are encrypted but no password has been supplied.\",\n        400\n      )\n    }\n    if (rootEntries.includes(\"db.txt\")) {\n      throw new HTTPError(\n        \"Workspace exports cannot be imported as Project packages.\",\n        400\n      )\n    }\n    if (","sourceCodeStart":913,"sourceCodeEnd":949,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/projects/backups/imports.ts#L913-L949","documentation":"After extraction, if an encryptPassword was supplied, decryptFiles() is run over the package contents; any failure is converted into this HTTP 400 at imports.ts:931. It almost always means the password is wrong or the archive is not the encrypted package it claims to be — the raw decrypt error is swallowed and replaced by this generic message.","triggerScenarios":"Importing a package with encryptPassword set while decryptFiles(tmpPath, encryptPassword) throws at imports.ts:930 (wrong password, corrupted .enc files, package encrypted with a different scheme/key).","commonSituations":"Password mismatch after re-exporting with a new password; copy/paste errors or trailing whitespace in the password; partial/corrupted upload; importing a package encrypted by an older Budibase version with a different encryption format.","solutions":["Re-enter the exact password used when the package was exported, without trailing whitespace","Re-export the package from the source workspace with a known password and retry","Verify the .enc files are intact (re-upload/re-download; compare checksums if possible)","If you have the password but decryption still fails, the package may use an incompatible encryption version — re-export on a matching Budibase version"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// cannot pre-verify decryption without decrypting, but confirm password is present and well-formed\nif (!password || password.length === 0) throw new Error('a password is required for encrypted packages')\n// optionally peek into the tarball to confirm .enc files exist and match the export that used this password","typeGuard":"function isPlausiblePassword(p: unknown): p is string {\n  return typeof p === 'string' && p.length > 0 && p === p.trim()\n}","tryCatchPattern":"try {\n  await importProjectPackage(file, password)\n} catch (err) {\n  if (err instanceof HTTPError && err.status === 400 && err.message === 'Project package could not be decrypted.') {\n    // wrong password or corrupt archive: confirm password with exporter, or re-export\n  } else {\n    throw err\n  }\n}","preventionTips":["Store export passwords in a shared secret manager so importers have the exact value","Verify package integrity (checksum) after download before importing","Re-export rather than guessing passwords after re-encryption","Keep exporter and importer on compatible Budibase versions for the encryption format"],"tags":["encryption","decryption","http-400","password"],"backgroundTag":"decryption-failed","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}