{"record":{"id":"0834894b122159bc","repo":"PRQL/prql","slug":"internal-error-command-does-not-take-input-outp","errorCode":null,"errorMessage":"internal error: command does not take input & output","messagePattern":"internal error: command does not take input & output","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"prqlc/prqlc/src/cli/mod.rs","lineNumber":535,"sourceCode":"                }\n\n                match res {\n                    Ok(r) => r?.as_bytes().to_vec(),\n                    Err(payload) => panic::resume_unwind(payload),\n                }\n            }\n            _ => unreachable!(\"Other commands shouldn't reach `execute`\"),\n        })\n    }\n\n    fn read_input(&mut self) -> Result<(SourceTree, String)> {\n        // Possibly this should be called by the relevant subcommands passing in\n        // `input`, rather than matching on them and grabbing `input` from\n        // `self`? But possibly if everything moves to `io_args`, then this is\n        // quite reasonable?\n        let io_args = self\n            .io_args()\n            .ok_or_else(|| anyhow!(\"internal error: command does not take input & output\"))?;\n        let input = &mut io_args.input;\n\n        // Don't wait without a prompt when running `prqlc compile` —\n        // it's confusing whether it's waiting for input or not. This\n        // offers the prompt.\n        //\n        // See https://github.com/PRQL/prql/issues/3228 for details on us not\n        // yet using `input.is_tty()`.\n        if input.path() == Path::new(\"-\") && std::io::stdin().is_terminal() {\n            #[cfg(unix)]\n            eprintln!(\"Enter PRQL, then press ctrl-d to compile:\\n\");\n            #[cfg(windows)]\n            eprintln!(\"Enter PRQL, then press ctrl-z to compile:\\n\");\n        }\n\n        let sources = read_files(input)?;\n\n        let main_path = io_args.main_path.clone().unwrap_or_default();","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/PRQL/prql/blob/e164e249b99485890036eb60f57c37520379b240/prqlc/prqlc/src/cli/mod.rs#L517-L553","documentation":"`read_input` reads the query source from the command's IoArgs (input path or stdin). If the active subcommand has no `IoArgs` attached, `io_args()` returns None and this internal-error is raised. It marks a programming mistake in wiring the command enum, not bad user input.","triggerScenarios":"A new/modified `Command` variant is dispatched through `run_io_command` -> `read_input` without providing `IoArgs`, so `Command::io_args()` matches None.","commonSituations":"Adding a new subcommand that forgets to populate `io_args` in the parser; refactoring the enum so a variant no longer carries input/output options.","solutions":["Ensure the subcommand struct includes an `IoArgs` field and that `io_args()` maps the variant to it","Route commands that truly take no I/O away from `run_io_command`","If it reproduces on a released binary, file a bug with the exact command line"],"exampleFix":"// before\nstruct CompileArgs { options: CompileOpts }\n// after\nstruct CompileArgs { options: CompileOpts, #[clap(flatten)] io: IoArgs }","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"match cmd.io_args() { Some(io) => ..., None => anyhow::bail!(\"internal error: command does not take input & output\") }","preventionTips":["Always attach IoArgs via clap flatten to every I/O subcommand","Add a unit test iterating all Command variants asserting io_args() is Some where expected"],"tags":["cli","internal-error","io","bug"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e164e249b99485890036eb60f57c37520379b240","analyzedAt":"2026-09-09T12:18:38.727Z","contentChangedAt":"2026-09-09T12:18:38.727Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}