{"record":{"id":"53c8b5ec038bc10a","repo":"Budibase/budibase","slug":"plugin-must-be-compressed-into-a-gzipped-tarball","errorCode":null,"errorMessage":"Plugin must be compressed into a gzipped tarball.","messagePattern":"Plugin must be compressed into a gzipped tarball\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/api/controllers/plugin/file.ts","lineNumber":17,"sourceCode":"import {\n  createTempFolder,\n  deleteFolderFileSystem,\n  getPluginMetadata,\n  extractTarball,\n} from \"../../../utilities/fileSystem\"\nimport { KoaFile } from \"@budibase/types\"\n\nexport async function fileUpload(file: KoaFile) {\n  const filename = file.originalFilename\n  const filePath = file.filepath\n\n  if (!filename || !filePath) {\n    throw new Error(\"File is not valid - cannot upload.\")\n  }\n  if (!filename.endsWith(\".tar.gz\")) {\n    throw new Error(\"Plugin must be compressed into a gzipped tarball.\")\n  }\n  const path = createTempFolder(filename.split(\".tar.gz\")[0])\n\n  try {\n    await extractTarball(filePath, path)\n    return await getPluginMetadata(path)\n  } catch (err) {\n    deleteFolderFileSystem(path)\n    throw err\n  }\n}\n","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/plugin/file.ts#L1-L29","documentation":"Plugins must be distributed as gzipped tarballs. fileUpload checks the original filename ends with \".tar.gz\" and rejects anything else with this message, before attempting extractTarball. This ensures the archive can be extracted and plugin metadata read safely.","triggerScenarios":"Uploading a plugin file with any extension other than .tar.gz — e.g. .zip, .tgz (without the full suffix), plain .tar, or a renamed file whose extension doesn't match its contents.","commonSituations":"Packaging a plugin with zip instead of tar czf; renaming .tgz to .tar.gz incorrectly or forgetting the rename; downloading a release asset that was decompressed by the browser; macOS squashing the extension to .tgz.","solutions":["Repackage the plugin: tar -czf your-plugin.tar.gz <plugin-folder-or-files>","Verify the filename ends exactly in .tar.gz (rename .tgz if needed)","Confirm the archive actually contains the plugin.json/manifest at the expected location","Re-upload the correctly packaged tarball"],"exampleFix":"// before\nzip -r plugin.zip dist/   # rejected\n// after\ntar -czf plugin.tar.gz dist/","handlingStrategy":"validation","validationCode":"const name = file.name\nif (!name.endsWith(\".tar.gz\")) {\n  throw new Error(`Plugin must be a .tar.gz; got ${name}`)\n}\n","typeGuard":"const isTarGz = (name: string): name is `${string}.tar.gz` =>\n  name.endsWith(\".tar.gz\")\n","tryCatchPattern":"try {\n  await api.post(\"/api/plugins\", form)\n} catch (err) {\n  if (err.message === \"Plugin must be compressed into a gzipped tarball.\") {\n    // repackage: tar -czf plugin.tar.gz dist/\n  } else { throw err }\n}\n","preventionTips":["Package plugins with tar -czf, never zip","Keep the .tar.gz extension (don't let tools save as .tgz)","Verify archive contents (plugin manifest at expected path) before upload","Document packaging steps in the plugin repo README"],"tags":["plugin","upload","archive","validation"],"backgroundTag":"invalid-file-format","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}