{"record":{"id":"0dafe512a73b7c24","repo":"flipped-aurora/gin-vue-admin","slug":"invalid-plugin-archive","errorCode":null,"errorMessage":"invalid plugin archive","messagePattern":"invalid plugin archive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/auto_code_plugin.go","lineNumber":306,"sourceCode":"\t\t\t\troot: filepath.Join(tempDir, filepath.FromSlash(strings.Join(parts[:index+2], \"/\"))),\n\t\t\t\tname: name,\n\t\t\t}\n\t\t\tif parts[index] == \"server\" {\n\t\t\t\tif archive.server != nil && (archive.server.name != part.name || archive.server.root != part.root) {\n\t\t\t\t\treturn pluginArchive{}, errors.New(\"plugin archive contains multiple server plugins\")\n\t\t\t\t}\n\t\t\t\tarchive.server = part\n\t\t\t} else {\n\t\t\t\tif archive.web != nil && (archive.web.name != part.name || archive.web.root != part.root) {\n\t\t\t\t\treturn pluginArchive{}, errors.New(\"plugin archive contains multiple web plugins\")\n\t\t\t\t}\n\t\t\t\tarchive.web = part\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\tif archive.server == nil && archive.web == nil {\n\t\treturn pluginArchive{}, errors.New(\"invalid plugin archive\")\n\t}\n\treturn archive, nil\n}\n\nfunc pluginInstallRoot(component, parentPlugin string) (string, error) {\n\troot, err := utils.JoinWithinRoot(global.GVA_CONFIG.AutoCode.Root, component, \"plugin\")\n\tif err != nil || parentPlugin == \"\" {\n\t\treturn root, err\n\t}\n\tparentPath, err := utils.JoinWithinRoot(root, parentPlugin)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tinfo, err := os.Stat(parentPath)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"parent plugin does not exist\")\n\t}\n\tif !info.IsDir() {","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/auto_code_plugin.go#L288-L324","documentation":"After scanning the archive, the installer requires at least one recognized plugin part (server or web). If neither a `server/<name>/` nor a web plugin directory was found in the extracted contents, the archive is deemed not a plugin package and this error is thrown.","triggerScenarios":"Uploading a zip that does not follow the plugin layout — no directory path containing `server/` or the web plugin root pattern; uploading an arbitrary project zip, a source-only archive with flat structure, or an empty/corrupted archive whose entries were not matched.","commonSituations":"Wrong file uploaded (docs zip, source snapshot, release artifact of something else); archive built with paths that are too deeply nested or use unexpected root folder names; zip extracted with tools that stripped directory entries; testing the endpoint with a random file renamed to .zip.","solutions":["Verify the archive contains `server/plugin/<name>` and/or the corresponding web plugin directory with the expected folder structure.","Re-export the plugin package using the standard plugin packaging flow.","Check that you uploaded the correct .zip file and that it is not truncated (test by extracting locally).","Flatten any excessive nesting so the `server/` and web roots sit at the expected depths inside the archive."],"exampleFix":"// before (flat, unrecognized layout)\nmain.go\npackage.json\n// after (recognized layout)\nserver/plugin/my-plugin/\nweb/src/plugin/my-plugin/","handlingStrategy":"validation","validationCode":"const hasServer = entries.some(e => /(^|\\/)server\\/[^/]+\\//.test(e))\nconst hasWeb = entries.some(e => /(^|\\/)web\\/src\\/plugin\\/[^/]+\\//.test(e))\nif (!hasServer && !hasWeb) throw new Error('archive is not a plugin package: no server or web plugin directory found')","typeGuard":null,"tryCatchPattern":"try {\n  await installPlugin(file)\n} catch (e) {\n  if (e.message.includes('invalid plugin archive')) {\n    showHint('Uploaded file does not follow the plugin archive layout; check its folder structure.')\n  } else { throw e }\n}","preventionTips":["Confirm the file is the plugin export zip, not a docs or source snapshot.","Extract locally and inspect the top-level layout before every upload.","Ensure zip creation includes directory entries (some tools strip them)."],"tags":["plugin-install","archive-validation"],"backgroundTag":"plugin-archive-structure-invalid","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}