From d04b960c0551b343272e8a1ea53d380932ded923 Mon Sep 17 00:00:00 2001 From: Ian Maloney Date: Thu, 19 Feb 2026 20:55:18 +0000 Subject: [PATCH 1/7] warn when pager is missing instead of silently falling back when a configured pager (via BAT_PAGER, PAGER, or --pager) is not found, bat now shows a warning message before falling back to stdout. this helps users understand why their pager isn't running and makes it obvious when there's a typo or PATH issue. fixes issue #2904 --- CHANGELOG.md | 1 + src/output.rs | 12 +++++++++++- tests/integration_tests.rs | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8d93805..3e8fad14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Improve native man pages and command help syntax highlighting by stripping overstriking, see #3517 (@akirk) ## Bugfixes +- Report error when pager is missing instead of silently falling back, see #3588 (@IMaloney) - Fix crash with BusyBox `less` on Windows, see #3527 (@Anchal-T) - Fix `bat cache --help` failing with 'unexpected argument' error, see #3580 and #3560 (@NORMAL-EX) - `--help` now correctly honors `--pager=builtin`. See #3516 (@keith-hall) diff --git a/src/output.rs b/src/output.rs index e5c8a654..64ef2f15 100644 --- a/src/output.rs +++ b/src/output.rs @@ -105,6 +105,10 @@ impl OutputType { let resolved_path = match grep_cli::resolve_binary(&pager.bin) { Ok(path) => path, Err(_) => { + crate::bat_warning!( + "Pager '{}' not found, outputting to stdout instead", + pager.bin.to_string_lossy() + ); return Ok(OutputType::stdout()); } }; @@ -174,7 +178,13 @@ impl OutputType { Ok(p.stdin(Stdio::piped()) .spawn() .map(OutputType::Pager) - .unwrap_or_else(|_| OutputType::stdout())) + .unwrap_or_else(|_| { + crate::bat_warning!( + "Pager '{}' not found, outputting to stdout instead", + &pager.bin + ); + OutputType::stdout() + })) } pub(crate) fn stdout() -> Self { diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index da8b21eb..b6de86ee 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1425,6 +1425,21 @@ fn pager_failed_to_parse() { .stderr(predicate::str::contains("Could not parse pager command")); } +#[test] +#[serial] +fn pager_missing_warning() { + bat() + .env("BAT_PAGER", "nonexistent-pager-xyz-missing") + .arg("--paging=always") + .arg("test.txt") + .assert() + .success() + .stderr(predicate::str::contains("[bat warning]")) + .stderr(predicate::str::contains("not found")) + .stderr(predicate::str::contains("nonexistent-pager-xyz-missing")) + .stdout(predicate::str::contains("hello world\n")); +} + #[test] #[serial] fn env_var_bat_paging() { From 335eff51f3d6f819f7e634c1f562f2132051f9e7 Mon Sep 17 00:00:00 2001 From: Ian Maloney Date: Thu, 19 Feb 2026 21:44:47 +0000 Subject: [PATCH 2/7] fix type error, pager.bin is already a string --- src/output.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output.rs b/src/output.rs index 64ef2f15..fbae5483 100644 --- a/src/output.rs +++ b/src/output.rs @@ -107,7 +107,7 @@ impl OutputType { Err(_) => { crate::bat_warning!( "Pager '{}' not found, outputting to stdout instead", - pager.bin.to_string_lossy() + pager.bin ); return Ok(OutputType::stdout()); } From 00e38cd05631bf4cf29775d79090b8e90d87c8ca Mon Sep 17 00:00:00 2001 From: Ian Maloney Date: Thu, 19 Feb 2026 22:01:58 +0000 Subject: [PATCH 3/7] only warn for explicitly configured pagers, not defaults --- src/output.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/output.rs b/src/output.rs index fbae5483..a5767bf5 100644 --- a/src/output.rs +++ b/src/output.rs @@ -105,10 +105,12 @@ impl OutputType { let resolved_path = match grep_cli::resolve_binary(&pager.bin) { Ok(path) => path, Err(_) => { - crate::bat_warning!( - "Pager '{}' not found, outputting to stdout instead", - pager.bin - ); + if pager.source != PagerSource::Default { + crate::bat_warning!( + "Pager '{}' not found, outputting to stdout instead", + pager.bin + ); + } return Ok(OutputType::stdout()); } }; From a240aa4afd4978179f044fc62eb53f7b2562fd9a Mon Sep 17 00:00:00 2001 From: Ian Maloney Date: Thu, 19 Feb 2026 22:21:17 +0000 Subject: [PATCH 4/7] never warn for missing 'less' pager (common default) --- src/output.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output.rs b/src/output.rs index a5767bf5..7c1e6b17 100644 --- a/src/output.rs +++ b/src/output.rs @@ -105,7 +105,7 @@ impl OutputType { let resolved_path = match grep_cli::resolve_binary(&pager.bin) { Ok(path) => path, Err(_) => { - if pager.source != PagerSource::Default { + if pager.source != PagerSource::Default && pager.bin != "less" { crate::bat_warning!( "Pager '{}' not found, outputting to stdout instead", pager.bin From 2c1a8caadde0e888306470bbba2689514c24ff00 Mon Sep 17 00:00:00 2001 From: Ian Maloney Date: Thu, 19 Feb 2026 22:49:02 +0000 Subject: [PATCH 5/7] simplify: just never warn for less (universal default) --- src/output.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output.rs b/src/output.rs index 7c1e6b17..c79de01c 100644 --- a/src/output.rs +++ b/src/output.rs @@ -105,7 +105,7 @@ impl OutputType { let resolved_path = match grep_cli::resolve_binary(&pager.bin) { Ok(path) => path, Err(_) => { - if pager.source != PagerSource::Default && pager.bin != "less" { + if pager.bin != "less" { crate::bat_warning!( "Pager '{}' not found, outputting to stdout instead", pager.bin From 319811df01f2b9bf036ebef677130dd87f9966d1 Mon Sep 17 00:00:00 2001 From: Ian Maloney Date: Fri, 20 Feb 2026 00:09:02 +0000 Subject: [PATCH 6/7] fix test: use builtin pager instead of less, revert to warn for all missing pagers --- src/output.rs | 10 ++++------ tests/integration_tests.rs | 1 + 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/output.rs b/src/output.rs index c79de01c..fbae5483 100644 --- a/src/output.rs +++ b/src/output.rs @@ -105,12 +105,10 @@ impl OutputType { let resolved_path = match grep_cli::resolve_binary(&pager.bin) { Ok(path) => path, Err(_) => { - if pager.bin != "less" { - crate::bat_warning!( - "Pager '{}' not found, outputting to stdout instead", - pager.bin - ); - } + crate::bat_warning!( + "Pager '{}' not found, outputting to stdout instead", + pager.bin + ); return Ok(OutputType::stdout()); } }; diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index b6de86ee..4c295709 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1458,6 +1458,7 @@ fn env_var_bat_paging() { fn basic_set_terminal_title() { bat() .arg("--paging=always") + .arg("--pager=builtin") .arg("--set-terminal-title") .arg("test.txt") .assert() From bc84854d4b84e0bac23c2017ba74a12ae2aaab10 Mon Sep 17 00:00:00 2001 From: Ian Maloney Date: Fri, 20 Feb 2026 00:19:47 +0000 Subject: [PATCH 7/7] use cat as test pager instead of builtin (builtin is interactive, doesnt output to stdout) --- tests/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 4c295709..b2377a80 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1457,8 +1457,8 @@ fn env_var_bat_paging() { #[test] fn basic_set_terminal_title() { bat() + .env("BAT_PAGER", "cat") .arg("--paging=always") - .arg("--pager=builtin") .arg("--set-terminal-title") .arg("test.txt") .assert()