{"record":{"id":"408f118724606ce5","repo":"Budibase/budibase","slug":"plugin-missing-js-file","errorCode":null,"errorMessage":"Plugin missing .js file.","messagePattern":"Plugin missing \\.js file\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/pro/src/sdk/plugins/index.ts","lineNumber":42,"sourceCode":"  origin?: PluginOrigin\n): Promise<Plugin> {\n  const db = tenancy.getGlobalDB()\n  const version = metadata.package.version,\n    name = metadata.package.name,\n    description = metadata.package.description,\n    hash = metadata.schema.hash\n\n  // first open the tarball into tmp directory\n  const bucketPath = objectStore.getPluginS3Dir(name)\n  const files = await objectStore.uploadDirectory(\n    objectStore.ObjectStoreBuckets.PLUGINS,\n    directory,\n    bucketPath\n  )\n  const jsFile = files.find((file: any) => file.name.endsWith(\".js\"))\n  const iconFile = files.find((file: any) => file.name.endsWith(\".svg\"))\n  if (!jsFile) {\n    throw new Error(`Plugin missing .js file.`)\n  }\n  // validate the JS for a datasource\n  if (metadata.schema.type === PluginType.DATASOURCE) {\n    const js = loadJSFile(directory, jsFile.name)\n    const isolate = new ivm.Isolate({ memoryLimit: 8 })\n    try {\n      isolate.compileScriptSync(Module.wrap(js), { filename: jsFile.name })\n    } catch (err: any) {\n      const message = err?.message ? err.message : JSON.stringify(err)\n      throw new Error(`JS invalid: ${message}`)\n    } finally {\n      isolate.dispose()\n    }\n  }\n  const iconFileName = iconFile ? iconFile.name : null\n  const pluginId = dbCore.generatePluginID(name)\n\n  // overwrite existing docs entirely if they exist","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/pro/src/sdk/plugins/index.ts#L24-L60","documentation":"When storing an uploaded plugin, storePlugin lists the files uploaded to the object store under the plugin's bucket path and searches for a file ending in .js. Budibase plugins are bundled as a single .js bundle (plus an optional .svg icon), so if no .js file is present the upload is considered malformed and rejected. This prevents persisting a plugin that could never be loaded.","triggerScenarios":"Calling the plugin upload/store API with an archive that contains only metadata.json (and maybe an .svg icon) but no compiled .js bundle; uploading a plugin built with the wrong output filename or directory structure.","commonSituations":"A plugin author zipped the source folder instead of the built dist output; the plugin build (yarn build in the plugin repo) was never run; the archive path layout puts the .js file in a subdirectory not covered by the bucketPath listing.","solutions":["Rebuild the plugin (npm/yarn build in the plugin repository) so a bundled .js file is produced","Verify the plugin archive contains the .js bundle at the top level alongside metadata.json","Re-zip the plugin using the plugin CLI's bundling output rather than the raw source folder","Check the object-store bucket path configuration so the file listing actually covers where the .js was uploaded"],"exampleFix":"# before: zipping the plugin source directory\nzip -r my-plugin.zip my-plugin/\n// after: zip the built bundle output\n# after building the plugin, zip dist contents containing metadata.json + plugin .js\nzip -j my-plugin.zip dist/metadata.json dist/*.js","handlingStrategy":"validation","validationCode":"const files = await objectStore.listBucket(pluginDir)\nif (!files.some(f => f.name.endsWith(\".js\"))) {\n  throw new Error(\"Plugin archive must contain a compiled .js bundle\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always build the plugin before packaging","Zip the dist output, not the source folder","Validate archive contents (metadata.json + .js) before upload"],"tags":["plugins","upload","validation"],"backgroundTag":"plugin-bundle-invalid","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}