jdx/mise · error
invalid Python entry point name
Error message
invalid Python entry point name
What it means
Each discovered executable name from the installed environment is validated with is_plain_file_name before being symlinked into the install's bin/ directory. Names that are not plain file names (e.g. containing path separators, `..`, or other traversal-capable characters) are rejected to prevent a malicious or malformed package metadata from writing outside the install path.
Solutions
- Remove the offending package from your dependency set and re-lock: `mise lock --bump <tool>`.
- Inspect the installed distribution's entry_points.txt / RECORD to find the malformed entry point name.
- Report the package to PyPI/maintainers if the entry point name is genuinely malicious; treat the package as untrusted.
- Install a known-good version of the package that does not declare pathological entry point names.
Example fix
// before (entry_points.txt from malicious wheel) [console_scripts] ../../evil = pkg:main // after: pin a clean version and re-lock $ mise lock --bump <tool> # against a vetted version
Defensive patterns
Strategy: validation
Validate before calling
const names = discoverScripts();
if (names.some(n => /[\/\\]/.test(n) || n === '..' || n === '.')) throw new Error('suspicious entry point name'); Prevention
- Only lock packages from trusted maintainers/registries
- Review entry point names when adopting new tools
- Treat path-like entry point names in any wheel metadata as a red flag
When it happens
Trigger: Thrown from install_uv_lock when a name in the DISCOVER_SCRIPTS JSON output fails crate::file::is_plain_file_name — e.g. an entry point name containing `/`, `\\`, or other non-plain-file characters, typically from a crafted or corrupted distribution's entry_points metadata.
Common situations: A compromised or malicious PyPI package declares entry points with path-like names; corrupted metadata inside an installed wheel; unusual distributions with exotic entry point names.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- brew-cask: app target
- brew-cask: binary target
- brew-cask: completion target
- brew-cask: completion target
- brew-cask: completion target
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/211a0870d7e3eff5.
Report an issue: GitHub.
Appendix: source
Thrown at src/backend/pipx/lock.rs:500
} else {
"python"
});
let packages = self.locked_entry_point_packages(tv, lock)?;
let packages = serde_json::to_string(&packages)?;
let names = CmdLineRunner::new(python)
.args(["-I", "-c", DISCOVER_SCRIPTS, &packages])
.arg(&scripts)
.read()
.await?;
let names: Vec<String> = serde_json::from_str(names.trim())?;
if names.is_empty() {
bail!("{} exposes no executable scripts", self.ba.short);
}
let bin = tv.install_path().join("bin");
crate::file::create_dir_all(&bin)?;
for name in names {
if !crate::file::is_plain_file_name(&name) {
bail!("invalid Python entry point name");
}
crate::file::make_symlink_or_copy(&scripts.join(&name), &bin.join(&name))?;
}
Ok(())
}
fn locked_entry_point_packages(&self, tv: &ToolVersion, lock: &UvLock) -> Result<Vec<String>> {
let root_requirement = lock
.project
.get("project")
.and_then(toml::Value::as_table)
.and_then(|project| project.get("dependencies"))
.and_then(toml::Value::as_array)
.and_then(|dependencies| dependencies.first())
.and_then(toml::Value::as_str)
.ok_or_else(|| eyre!("missing locked Python root requirement"))?;
let root = PipxOptions::requirement_package_name(root_requirement)
.ok_or_else(|| eyre!("invalid locked Python root requirement"))?;View on GitHub (pinned to 533346cc37)