{"record":{"id":"ff566e00c7f91e90","repo":"jdx/mise","slug":"exposes-no-executable-scripts","errorCode":null,"errorMessage":"{} exposes no executable scripts","messagePattern":"(.+?) exposes no executable scripts","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/backend/pipx/lock.rs","lineNumber":494,"sourceCode":"            .execute()?;\n        let scripts = project\n            .join(\".venv\")\n            .join(if cfg!(windows) { \"Scripts\" } else { \"bin\" });\n        let python = scripts.join(if cfg!(windows) {\n            \"python.exe\"\n        } else {\n            \"python\"\n        });\n        let packages = self.locked_entry_point_packages(tv, lock)?;\n        let packages = serde_json::to_string(&packages)?;\n        let names = CmdLineRunner::new(python)\n            .args([\"-I\", \"-c\", DISCOVER_SCRIPTS, &packages])\n            .arg(&scripts)\n            .read()\n            .await?;\n        let names: Vec<String> = serde_json::from_str(names.trim())?;\n        if names.is_empty() {\n            bail!(\"{} exposes no executable scripts\", self.ba.short);\n        }\n        let bin = tv.install_path().join(\"bin\");\n        crate::file::create_dir_all(&bin)?;\n        for name in names {\n            if !crate::file::is_plain_file_name(&name) {\n                bail!(\"invalid Python entry point name\");\n            }\n            crate::file::make_symlink_or_copy(&scripts.join(&name), &bin.join(&name))?;\n        }\n        Ok(())\n    }\n\n    fn locked_entry_point_packages(&self, tv: &ToolVersion, lock: &UvLock) -> Result<Vec<String>> {\n        let root_requirement = lock\n            .project\n            .get(\"project\")\n            .and_then(toml::Value::as_table)\n            .and_then(|project| project.get(\"dependencies\"))","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/backend/pipx/lock.rs#L476-L512","documentation":"After installing the uv-locked environment, install_uv_lock runs a Python discovery script that lists the console/gui scripts and script files exposed by the requested packages. If the resulting set is empty, the tool provides nothing to symlink into bin/, so mise fails the install rather than producing an install with no usable executables.","triggerScenarios":"Thrown from install_uv_lock (called by install_version_) when the JSON returned by the DISCOVER_SCRIPTS python snippet deserializes to an empty list — i.e. none of the locked packages expose console_scripts/gui_scripts entry points or script files in the venv scripts directory.","commonSituations":"Locking/installing a library-only PyPI package (no CLI) as a tool; all entry points gated behind inactive environment markers; the wrong package name expected by importlib.metadata (dependency split/renamed); installing via `pipx:` when the CLI actually lives in a different distribution.","solutions":["Verify the PyPI package actually ships a CLI; if it's a library, don't install it as a tool (use it as a dependency instead).","Run `mise lock --bump <tool>` to rebuild the lock with the correct root package and version.","Check the package's metadata for console_scripts entry points (e.g. inspect the wheel's entry_points.txt).","If the CLI moved to a differently-named distribution, point the tool at the correct PyPI name."],"exampleFix":"// before: library without entry points installed as a tool\n[tools]\nsomeclilib = \"pipx:someclilib\"  # no console_scripts\n\n// after: use the actual CLI distribution\n[tools]\nsomeclilib = \"pipx:somecli\"","handlingStrategy":"validation","validationCode":"// confirm the package ships console scripts before treating it as a CLI tool\nconst eps = wheelMetadata('entry_points.txt');\nif (!/\\[console_scripts\\]/.test(eps)) console.warn('package exposes no CLI');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only install PyPI packages that document a CLI as tools","Check entry_points.txt / docs for console_scripts before adding a pipx tool","Use libraries as dependencies, not installable tools"],"tags":["python","uv","entry-points","install"],"backgroundTag":"empty-result-set","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}