PRQL/prql · error

`lsp` requires `prqlc` to be built with the `lsp` feature

Error message

`lsp` requires `prqlc` to be built with the `lsp` feature

What it means

prqlc's `lsp` subcommand starts the LSP server, but the server implementation is only compiled when the `lsp` cargo feature is enabled. The CLI is deliberately built without that feature by default (it pulls in heavy tower-lsp dependencies), so invoking `lsp` on such a build returns this error instead of panicking.

Solutions

  1. Rebuild/install with the feature enabled: `cargo install prqlc --features lsp`
  2. If building from source: `cargo build -p prqlc --features lsp` and point the editor at the new binary
  3. Use a published build known to include lsp support, or remove the `lsp` command from editor config if the feature is not needed

Example fix

// before
cargo install prqlc
// after
cargo install prqlc --features lsp
Defensive patterns

Strategy: fallback

Validate before calling

const hasLsp = (help: string) => /\blsp\b/.test(help);

Type guard

function supportsLsp(binary: string): boolean { return runCmd(binary, ['--help']).stdout.includes('lsp'); }

Try / catch

try { await startLsp(); } catch (e) { if (String(e).includes('lsp` requires')) { console.error('Install with: cargo install prqlc --features lsp'); } else { throw e; } }

Prevention

When it happens

Trigger: Running `prqlc lsp` against a binary compiled without `--features lsp` (e.g. the default `cargo install prqlc`, distro packages, or `cargo build` without feature flags).

Common situations: Editor plugin expects `prqlc lsp` but the installed binary came from a default-features release; CI built the binary without features; an older or minimal package build where lsp was stripped to reduce binary size.

Related errors


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

Appendix: source

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

            Command::Debug(DebugCommand::JsonSchema { ir_type }) => {
                let schema = match ir_type {
                    IntermediateRepr::Pl => schema_for!(pl::ModuleDef),
                    IntermediateRepr::Rq => schema_for!(rq::RelationalQuery),
                    IntermediateRepr::Lineage => schema_for!(FrameCollector),
                };
                io::stdout().write_all(&serde_json::to_string_pretty(&schema)?.into_bytes())?;
                Ok(())
            }
            #[cfg(feature = "lsp")]
            Command::Lsp => match lsp::run() {
                Ok(_) => Ok(()),
                Err(err) => Err(anyhow!(err)),
            },
            // Without the feature there's no server to start. This has to be
            // handled here rather than falling through to `run_io_command`,
            // which has no `IoArgs` to work with and would panic.
            #[cfg(not(feature = "lsp"))]
            Command::Lsp => Err(anyhow!(
                "`lsp` requires `prqlc` to be built with the `lsp` feature"
            )),
            _ => self.run_io_command(),
        }
    }

    fn list_targets(&self) -> std::result::Result<(), anyhow::Error> {
        println!("{}", Target::names().join("\n"));
        Ok(())
    }

    fn run_io_command(&mut self) -> std::result::Result<(), anyhow::Error> {
        let (mut file_tree, main_path) = self.read_input()?;

        self.execute(&mut file_tree, &main_path)
            .and_then(|buf| self.write_output(&buf))
    }

View on GitHub (pinned to e164e249b9)