PRQL/prql · error

internal error: command does not take input & output

Error message

internal error: command does not take input & output

What it means

`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.

Solutions

  1. Ensure the subcommand struct includes an `IoArgs` field and that `io_args()` maps the variant to it
  2. Route commands that truly take no I/O away from `run_io_command`
  3. If it reproduces on a released binary, file a bug with the exact command line

Example fix

// before
struct CompileArgs { options: CompileOpts }
// after
struct CompileArgs { options: CompileOpts, #[clap(flatten)] io: IoArgs }
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

match cmd.io_args() { Some(io) => ..., None => anyhow::bail!("internal error: command does not take input & output") }

Prevention

When it happens

Trigger: A new/modified `Command` variant is dispatched through `run_io_command` -> `read_input` without providing `IoArgs`, so `Command::io_args()` matches None.

Common situations: 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.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of PRQL/prql@e164e249b9 (2026-09-09). Data as JSON: /api/errors/0834894b122159bc. Report an issue: GitHub.

Appendix: source

Thrown at prqlc/prqlc/src/cli/mod.rs:535

                }

                match res {
                    Ok(r) => r?.as_bytes().to_vec(),
                    Err(payload) => panic::resume_unwind(payload),
                }
            }
            _ => unreachable!("Other commands shouldn't reach `execute`"),
        })
    }

    fn read_input(&mut self) -> Result<(SourceTree, String)> {
        // Possibly this should be called by the relevant subcommands passing in
        // `input`, rather than matching on them and grabbing `input` from
        // `self`? But possibly if everything moves to `io_args`, then this is
        // quite reasonable?
        let io_args = self
            .io_args()
            .ok_or_else(|| anyhow!("internal error: command does not take input & output"))?;
        let input = &mut io_args.input;

        // Don't wait without a prompt when running `prqlc compile` —
        // it's confusing whether it's waiting for input or not. This
        // offers the prompt.
        //
        // See https://github.com/PRQL/prql/issues/3228 for details on us not
        // yet using `input.is_tty()`.
        if input.path() == Path::new("-") && std::io::stdin().is_terminal() {
            #[cfg(unix)]
            eprintln!("Enter PRQL, then press ctrl-d to compile:\n");
            #[cfg(windows)]
            eprintln!("Enter PRQL, then press ctrl-z to compile:\n");
        }

        let sources = read_files(input)?;

        let main_path = io_args.main_path.clone().unwrap_or_default();

View on GitHub (pinned to e164e249b9)