{"record":{"id":"efb7d4ce0849c706","repo":"multica-ai/multica","slug":"plugin-source-q-is-not-a-directory-or-regular-zip","errorCode":null,"errorMessage":"plugin source %q is not a directory or regular ZIP","messagePattern":"plugin source %q is not a directory or regular ZIP","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_plugin.go","lineNumber":149,"sourceCode":"\tPluginKey      string `json:\"plugin_key\"`\n\tVersion        string `json:\"version\"`\n\tManifestDigest string `json:\"manifest_digest\"`\n\tArchiveDigest  string `json:\"archive_digest\"`\n\tArtifactDigest string `json:\"artifact_digest\"`\n\tSizeBytes      int64  `json:\"size_bytes\"`\n\tFileCount      int    `json:\"file_count\"`\n}\n\nfunc loadPluginSource(source string) ([]byte, plugincontract.Artifact, error) {\n\tinfo, err := os.Stat(source)\n\tif err != nil {\n\t\treturn nil, plugincontract.Artifact{}, err\n\t}\n\tif info.IsDir() {\n\t\treturn plugincontract.PackDirectory(source)\n\t}\n\tif !info.Mode().IsRegular() {\n\t\treturn nil, plugincontract.Artifact{}, fmt.Errorf(\"plugin source %q is not a directory or regular ZIP\", source)\n\t}\n\tif info.Size() > plugincontract.MaxArchiveSize {\n\t\treturn nil, plugincontract.Artifact{}, fmt.Errorf(\"plugin archive exceeds %d bytes\", plugincontract.MaxArchiveSize)\n\t}\n\tarchive, err := os.ReadFile(source)\n\tif err != nil {\n\t\treturn nil, plugincontract.Artifact{}, err\n\t}\n\tartifact, err := plugincontract.ValidateArtifact(archive)\n\treturn archive, artifact, err\n}\n\nfunc pluginDigestResult(artifact plugincontract.Artifact) pluginDigestOutput {\n\treturn pluginDigestOutput{\n\t\tPluginKey: artifact.Manifest.Metadata.Key, Version: artifact.Manifest.Metadata.Version,\n\t\tManifestDigest: plugincontract.DigestBytes(artifact.CanonicalManifest), ArchiveDigest: artifact.ArchiveDigest,\n\t\tArtifactDigest: artifact.ArtifactDigest, SizeBytes: artifact.SizeBytes, FileCount: len(artifact.Files),\n\t}","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_plugin.go#L131-L167","documentation":"From loadPluginSource (cmd_plugin.go:149): the --source argument of `plugin validate`/`plugin install` stat'ed successfully but is neither a directory nor a regular file — i.e. a device, socket, pipe, or symlink-to-such. Only directories (packed on the fly) and regular ZIP files are accepted plugin sources.","triggerScenarios":"Passing /dev/null, a named pipe, or a character device as the plugin source; a symlink whose target is a socket/pipe; on some setups a dangling mount point with a special mode.","commonSituations":"Shell completion or a typo picks up a special file; using process substitution `<(zip ...)` which creates a FIFO; copying a plugin archive with cp from a pipe.","solutions":["Materialize the plugin as a real directory or a regular .zip file and pass that path.","If using process substitution, write the zip to disk first: `zip -r /tmp/plugin.zip dir && multica plugin validate /tmp/plugin.zip`.","Check what the path actually is: `ls -l <path>` — anything not starting with '-' or 'd' will be rejected."],"exampleFix":"// before\nmultica plugin validate <(make-plugin-zip)   // FIFO -> not a directory or regular ZIP\n\n// after\nmake-plugin-zip > /tmp/plugin.zip\nmultica plugin validate /tmp/plugin.zip","handlingStrategy":"type-guard","validationCode":"info, err := os.Stat(source)\nif err != nil { return err }\nif !info.IsDir() && !info.Mode().IsRegular() {\n    return fmt.Errorf(\"%s is mode %v; need directory or regular file\", source, info.Mode())\n}","typeGuard":"func isPluginSourcePath(p string) bool {\n    info, err := os.Stat(p)\n    return err == nil && (info.IsDir() || info.Mode().IsRegular())\n}","tryCatchPattern":null,"preventionTips":["Never pass process substitution or /dev fds as plugin sources.","Verify with ls -l that the source is '-' (file) or 'd' (dir) before validate/install.","Prefer directories over zips in CI to skip mode edge cases entirely."],"tags":["cli","filesystem","validation","plugin","go"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}