{"record":{"id":"3c92940e206126eb","repo":"jdx/mise","slug":"no-tool-specified-and-not-running-interactively","errorCode":null,"errorMessage":"No tool specified and not running interactively","messagePattern":"No tool specified and not running interactively","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/cli/use.rs","lineNumber":364,"sourceCode":"                    style(\"mise\").green(),\n                    style(&path).cyan().for_stderr(),\n                );\n            }\n            if !remove.is_empty() {\n                let tools_to_remove = remove.iter().map(|r| r.to_string()).join(\", \");\n                miseprintln!(\n                    \"{} {} removed: {tools_to_remove}\",\n                    style(\"mise\").green(),\n                    style(&path).cyan().for_stderr(),\n                );\n            }\n        }\n        Ok(())\n    }\n\n    fn tool_selector(&self) -> Result<ToolArg> {\n        if !console::user_attended_stderr() {\n            bail!(\"No tool specified and not running interactively\");\n        }\n        let theme = crate::ui::theme::get_theme();\n        let mut s = demand::Select::new(\"Tools\")\n            .description(\"Select a tool to install\")\n            .filtering(true)\n            .filterable(true)\n            .theme(&theme);\n        for rt in REGISTRY.values().unique_by(|r| r.short) {\n            if let Some(backend) = rt.backends().first() {\n                // TODO: populate registry with descriptions from aqua and other sources\n                // TODO: use the backend from the lockfile if available\n                let description = rt.description.unwrap_or(backend);\n                s = s.option(demand::DemandOption::new(rt).description(description));\n            }\n        }\n        ctrlc::show_cursor_after_ctrl_c();\n        match s.run() {\n            Ok(rt) => rt.short.parse(),","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/cli/use.rs#L346-L382","documentation":"`mise use` with no tool arguments opens an interactive tool selector (demand::Select). That requires a TTY on stderr; when stderr is not user-attended (CI, piped output, non-interactive shell) tool_selector bails at src/cli/use.rs:364 rather than hanging on an invisible prompt.","triggerScenarios":"Bare `mise use` in CI, cron, Docker build, or any context where stderr is redirected/piped (console::user_attended_stderr() == false).","commonSituations":"Bootstrap scripts assuming interactivity; running mise inside `docker build`; SSH one-shot commands without TTY; piping mise output to tee.","solutions":["Pass the tool explicitly: `mise use node@22` — no prompt needed","Run the command in a real interactive terminal if you wanted the selector","For scripts, resolve versions ahead of time and feed them as args (optionally from mise.lock/registry)"],"exampleFix":"# before\n$ mise use | tee log.txt   # or in CI\n# error: No tool specified and not running interactively\n\n# after\n$ mise use node@22","handlingStrategy":"validation","validationCode":"# never rely on the interactive selector in scripts\nif [ -t 2 ] && [ $# -eq 0 ]; then mise use; else mise use \"${1:?usage: mise use <tool>[@version]}\"; fi","typeGuard":null,"tryCatchPattern":"mise use \"$tool\" || { echo 'non-interactive: pass an explicit tool@version to mise use' >&2; exit 1; }","preventionTips":["Always pass tool args to `mise use` in CI/Docker/cron","Guard interactive commands with `[ -t 2 ]` in shared scripts"],"tags":["mise","interactive","tty","ci","use","cli"],"backgroundTag":"interactive-prompt-unavailable","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}