{"record":{"id":"370186606c920693","repo":"Budibase/budibase","slug":"supplied-file-is-a-plugin-cannot-import-as-app","errorCode":null,"errorMessage":"Supplied file is a plugin - cannot import as app.","messagePattern":"Supplied file is a plugin - cannot import as app\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/server/src/sdk/workspace/backups/imports.ts","lineNumber":279,"sourceCode":"  const objectStoreProdAppId = dbCore.getProdWorkspaceID(objectStoreWorkspaceId)\n  let dbStream: fs.ReadStream\n  const isTar = template.file && template?.file?.type?.endsWith(\"gzip\")\n  const isDirectory =\n    template.file && (await fsp.lstat(template.file.path)).isDirectory()\n  let tmpPath: string | undefined = undefined\n  if (template.file && (isTar || isDirectory)) {\n    tmpPath = isTar ? await untarFile(template.file) : template.file.path\n    if (isTar && template.file.password) {\n      await decryptFiles(tmpPath, template.file.password)\n    }\n    const contents = await fsp.readdir(tmpPath)\n    const stillEncrypted = !!contents.find(name => name.endsWith(\".enc\"))\n    if (stillEncrypted) {\n      throw new Error(\"Files are encrypted but no password has been supplied.\")\n    }\n    const isPlugin = !!contents.find(name => name === \"plugin.min.js\")\n    if (isPlugin) {\n      throw new Error(\"Supplied file is a plugin - cannot import as app.\")\n    }\n    const isInvalid = !contents.find(name => name === DB_EXPORT_FILE)\n    if (isInvalid) {\n      throw new Error(\n        \"App export does not appear to be valid - no DB file found.\"\n      )\n    }\n    // have to handle object import\n    if (importOpts.importObjStoreContents) {\n      const promises = []\n      const excludedFiles = [GLOBAL_DB_EXPORT_FILE, DB_EXPORT_FILE]\n\n      for (let filename of contents) {\n        const path = join(tmpPath, filename)\n        if (excludedFiles.includes(filename)) {\n          continue\n        }\n        filename = join(objectStoreProdAppId, filename)","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/backups/imports.ts#L261-L297","documentation":"importApp detects plugin.min.js in the extracted package and refuses to import it as an app. Plugins (custom components/datasources) are installed through the plugin upload flow, not the app import flow, so this guard prevents misfiling a plugin bundle as an application.","triggerScenarios":"Uploading a plugin archive (containing plugin.min.js) to the app import endpoint (importApp), e.g. selecting a plugin zip in an import dialog that expects an app export.","commonSituations":"Users confusing the plugin upload and app import screens; scripts pointing at the wrong endpoint; an export from a plugin-template repository being imported as an app.","solutions":["Upload the archive via the plugin management endpoint/upload flow instead of app import","Install the plugin in the builder (Plugins section) and import an actual app export separately","Confirm the archive contents — plugin.min.js means it is a plugin, not an app export"],"exampleFix":"// before\nawait importApp(pluginArchivePath) // throws\n// after\nawait fetch(\"/api/plugins\", { method: \"POST\", body: pluginFormData }) // plugin upload flow","handlingStrategy":"validation","validationCode":"const listing = execSync(`tar -tzf ${archivePath}`).toString()\nif (listing.includes(\"plugin.min.js\")) {\n  throw new Error(\"Use the plugin upload flow, not app import\")\n}","typeGuard":null,"tryCatchPattern":"try {\n  await importApp(template)\n} catch (err: any) {\n  if (err.message.includes(\"Supplied file is a plugin\")) {\n    // redirect to plugin install endpoint\n  } else {\n    throw err\n  }\n}","preventionTips":["Inspect archives before import to classify them","Separate plugin and app artifact pipelines","Use the builder's Plugins section for plugin installation"],"tags":["import","plugin","wrong-endpoint"],"backgroundTag":"wrong-resource-type","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}