Budibase/budibase · error

Plugin missing .js file.

Error message

Plugin missing .js file.

What it means

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.

Source

Thrown at packages/pro/src/sdk/plugins/index.ts:42

  origin?: PluginOrigin
): Promise<Plugin> {
  const db = tenancy.getGlobalDB()
  const version = metadata.package.version,
    name = metadata.package.name,
    description = metadata.package.description,
    hash = metadata.schema.hash

  // first open the tarball into tmp directory
  const bucketPath = objectStore.getPluginS3Dir(name)
  const files = await objectStore.uploadDirectory(
    objectStore.ObjectStoreBuckets.PLUGINS,
    directory,
    bucketPath
  )
  const jsFile = files.find((file: any) => file.name.endsWith(".js"))
  const iconFile = files.find((file: any) => file.name.endsWith(".svg"))
  if (!jsFile) {
    throw new Error(`Plugin missing .js file.`)
  }
  // validate the JS for a datasource
  if (metadata.schema.type === PluginType.DATASOURCE) {
    const js = loadJSFile(directory, jsFile.name)
    const isolate = new ivm.Isolate({ memoryLimit: 8 })
    try {
      isolate.compileScriptSync(Module.wrap(js), { filename: jsFile.name })
    } catch (err: any) {
      const message = err?.message ? err.message : JSON.stringify(err)
      throw new Error(`JS invalid: ${message}`)
    } finally {
      isolate.dispose()
    }
  }
  const iconFileName = iconFile ? iconFile.name : null
  const pluginId = dbCore.generatePluginID(name)

  // overwrite existing docs entirely if they exist

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Rebuild the plugin (npm/yarn build in the plugin repository) so a bundled .js file is produced
  2. Verify the plugin archive contains the .js bundle at the top level alongside metadata.json
  3. Re-zip the plugin using the plugin CLI's bundling output rather than the raw source folder
  4. Check the object-store bucket path configuration so the file listing actually covers where the .js was uploaded

Example fix

# before: zipping the plugin source directory
zip -r my-plugin.zip my-plugin/
// after: zip the built bundle output
# after building the plugin, zip dist contents containing metadata.json + plugin .js
zip -j my-plugin.zip dist/metadata.json dist/*.js
Defensive patterns

Strategy: validation

Validate before calling

const files = await objectStore.listBucket(pluginDir)
if (!files.some(f => f.name.endsWith(".js"))) {
  throw new Error("Plugin archive must contain a compiled .js bundle")
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/408f118724606ce5. Report an issue: GitHub.