{"record":{"id":"ab2fbb0214e566fe","repo":"router-for-me/CLIProxyAPI","slug":"zip-does-not-contain-s","errorCode":null,"errorMessage":"zip does not contain %s","messagePattern":"zip does not contain (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginstore/install.go","lineNumber":348,"sourceCode":"\t\tif !regularZipFile(file) {\n\t\t\treturn nil, 0, fmt.Errorf(\"zip entry %s is not a regular file\", file.Name)\n\t\t}\n\t\tif !hasDynamicLibraryExtension(cleanedName) {\n\t\t\tcontinue\n\t\t}\n\t\tif cleanedName != targetName && cleanedName != versionedTargetName {\n\t\t\tif path.Base(cleanedName) == targetName || path.Base(cleanedName) == versionedTargetName {\n\t\t\t\treturn nil, 0, fmt.Errorf(\"target dynamic library must be at zip root\")\n\t\t\t}\n\t\t\treturn nil, 0, fmt.Errorf(\"dynamic library filename must be %s or %s\", targetName, versionedTargetName)\n\t\t}\n\t\tif target != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"zip contains multiple target dynamic libraries\")\n\t\t}\n\t\ttarget = file\n\t}\n\tif target == nil {\n\t\treturn nil, 0, fmt.Errorf(\"zip does not contain %s\", targetName)\n\t}\n\n\thandle, errOpen := target.Open()\n\tif errOpen != nil {\n\t\treturn nil, 0, fmt.Errorf(\"open %s: %w\", targetName, errOpen)\n\t}\n\tdefer func() {\n\t\tif errClose := handle.Close(); errClose != nil {\n\t\t\tlog.WithError(errClose).Debug(\"failed to close plugin archive entry\")\n\t\t}\n\t}()\n\tdata, errRead := io.ReadAll(handle)\n\tif errRead != nil {\n\t\treturn nil, 0, fmt.Errorf(\"read %s: %w\", targetName, errRead)\n\t}\n\tmode := target.FileInfo().Mode().Perm()\n\tif mode == 0 {\n\t\tmode = 0o755","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/install.go#L330-L366","documentation":"Thrown by readTargetLibrary in internal/pluginstore/install.go when the archive zip was parsed successfully but no entry matches the expected dynamic library filename. The expected name is derived from the plugin id, GOOS extension (install.go:319-320): <id>.so/.dylib/.dll or <id>-v<version><ext>. All entries lacking a dynamic library extension are skipped, so an archive of only READMEs or a misnamed binary yields this error.","triggerScenarios":"InstallArchive or any Client.Install* path where the downloaded zip contains the library under a different name (e.g. 'libmyplugin.so' or 'plugin.bin'), targets a different OS extension than options.GOOS implies (a .dll in the zip while GOOS=linux expects .so), or the library sits in a subdirectory with a non-matching base name.","commonSituations":"Release assets built for one platform installed with another GOOS; plugin id in the registry not matching the binary name inside the artifact; an archive that ships source or docs instead of the compiled library because the release job skipped the build step.","solutions":["Verify the zip actually contains <id><ext> or <id>-v<version><ext> at the root: unzip -l artifact.zip","Align options.GOOS with the platform the asset was built for (the asset selection uses the same GOOS/GOARCH)","Fix the release packaging to rename the built library to the plugin id plus the correct extension before zipping"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func hasTargetLib(archiveData []byte, id, version, goos string) bool {\n    r, err := zip.NewReader(bytes.NewReader(archiveData), int64(len(archiveData)))\n    if err != nil { return false }\n    ext := map[string]string{\"darwin\": \".dylib\", \"windows\": \".dll\"}[goos]\n    if ext == \"\" { ext = \".so\" }\n    want := map[string]bool{id + ext: true, id + \"-v\" + version + ext: true}\n    for _, f := range r.File {\n        if want[path.Clean(f.Name)] { return true }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"if err := installAndLog(data, plugin, opts); err != nil {\n    if strings.Contains(err.Error(), \"zip does not contain\") {\n        log.Errorf(\"artifact for %s/%s lacks the expected library; check asset naming\", opts.GOOS, opts.GOARCH)\n    }\n}","preventionTips":["Name the built library exactly as the plugin id with the platform extension before zipping","Test-install each release asset for every GOOS/GOARCH you publish in CI","Confirm options.GOOS matches the asset you downloaded (asset selection and zip scanning use the same value)"],"tags":["pluginstore","zip","packaging","install"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}