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
- Rebuild the archive so it contains exactly one server plugin directory.
- Remove extra server plugin directories from the zip before uploading.
- 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
- Zip only the single plugin directory, never the whole plugin root.
- Clean staging/extract folders before rebuilding an archive to avoid leftovers.
- Add a CI packaging step that asserts exactly one server plugin per artifact.
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
- server and web plugin names must match
- plugin archive contains multiple web plugins
- invalid plugin archive
- parent plugin is not a directory
- plugin already exists
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/d5ef088dc97612c3.
Report an issue: GitHub.