flipped-aurora/gin-vue-admin · error

plugin archive contains multiple server plugins

Error message

plugin archive contains multiple server plugins

What it means

While scanning the uploaded archive, the installer collects `server/<name>/` directories as candidate server plugin parts. If it finds two distinct server plugin roots (different name or path), it aborts, because a single archive must carry at most one server plugin.

Source

Thrown at server/service/system/auto_code_plugin.go:293

		if err != nil {
			return pluginArchive{}, err
		}
		parts := strings.Split(filepath.ToSlash(relativePath), "/")
		for index := 0; index+2 < len(parts); index++ {
			if parts[index+1] != "plugin" || (parts[index] != "server" && parts[index] != "web") {
				continue
			}
			name := parts[index+2]
			if err := utils.ValidatePluginName(name); err != nil {
				return pluginArchive{}, err
			}
			part := &pluginArchivePart{
				root: filepath.Join(tempDir, filepath.FromSlash(strings.Join(parts[:index+2], "/"))),
				name: name,
			}
			if parts[index] == "server" {
				if archive.server != nil && (archive.server.name != part.name || archive.server.root != part.root) {
					return pluginArchive{}, errors.New("plugin archive contains multiple server plugins")
				}
				archive.server = part
			} else {
				if archive.web != nil && (archive.web.name != part.name || archive.web.root != part.root) {
					return pluginArchive{}, errors.New("plugin archive contains multiple web plugins")
				}
				archive.web = part
			}
			break
		}
	}
	if archive.server == nil && archive.web == nil {
		return pluginArchive{}, errors.New("invalid plugin archive")
	}
	return archive, nil
}

func pluginInstallRoot(component, parentPlugin string) (string, error) {

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Rebuild the archive so it contains exactly one server plugin directory.
  2. Remove extra server plugin directories from the zip before uploading.
  3. If multiple plugins must be installed, upload them as separate archives in separate install operations.

Example fix

// before (archive layout)
server/plugin/foo/
server/plugin/bar/
web/src/plugin/foo/
// after
server/plugin/foo/
web/src/plugin/foo/
// (bar must be installed via its own archive)
Defensive patterns

Strategy: validation

Validate before calling

const serverDirs = new Set(entries.filter(e => /(^|\/)server\/[^/]+\//.test(e)).map(e => e.split('/')[1]))
if (serverDirs.size > 1) throw new Error(`archive has ${serverDirs.size} server plugins: ${[...serverDirs]}`)

Try / catch

try {
  await installPlugin(archive)
} catch (e) {
  if (e.message.includes('multiple server plugins')) {
    showHint('Split the archive: one server plugin per zip.')
  } else { throw e }
}

Prevention

When it happens

Trigger: Installing a sub-plugin archive that contains more than one unique `server/...` plugin directory, e.g. `server/plugin/a` and `server/plugin/b`, or two paths with different names under the server root. findPluginArchive throws when the second distinct server part is encountered.

Common situations: Zipping an entire `plugin/` folder containing several plugins instead of one; accidentally including a nested or copied plugin directory; re-zipping an extracted archive that already had leftovers from a previous plugin.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/d5ef088dc97612c3. Report an issue: GitHub.