Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 51 additions & 38 deletions src/execute/rmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,50 +500,63 @@ function withinActiveRenv() {
}
}

async function printCallRDiagnostics() {
const rBin = await checkRBinary();
if (rBin === undefined) {
info("");
info(rInstallationMessage());
info("");
} else {
const caps = await knitrCapabilities(rBin);
if (caps === undefined) {
info(
`Problem with running R found at ${rBin} to check environment configurations.`,
);
info("Please check your installation of R.");
export async function printCallRDiagnostics(
checkRBinaryImpl: () => Promise<string | undefined> = checkRBinary,
) {
// This re-enters R discovery to explain a callR failure. A throw here
// (e.g. from checkRBinaryImpl/rBinaryPath) must never replace the
// original callR error the caller is already reporting.
try {
const rBin = await checkRBinaryImpl();
if (rBin === undefined) {
info("");
info(rInstallationMessage());
info("");
} else {
if (
!caps?.packages.rmarkdown || !caps?.packages.knitr ||
!caps?.packages.knitrVersOk || !caps?.packages.rmarkdownVersOk
) {
info("R installation:");
info(knitrCapabilitiesMessage(caps, " "));
if (!!!caps?.packages.knitr || !caps?.packages.knitrVersOk) {
info("");
info(
knitrInstallationMessage(
"",
"knitr",
!!caps.packages.knitr && !caps.packages.knitrVersOk,
),
);
}
if (!!!caps?.packages.rmarkdown || !caps?.packages.rmarkdownVersOk) {
const caps = await knitrCapabilities(rBin);
if (caps === undefined) {
info(
`Problem with running R found at ${rBin} to check environment configurations.`,
);
info("Please check your installation of R.");
info("");
} else {
if (
!caps?.packages.rmarkdown || !caps?.packages.knitr ||
!caps?.packages.knitrVersOk || !caps?.packages.rmarkdownVersOk
) {
info("R installation:");
info(knitrCapabilitiesMessage(caps, " "));
if (!!!caps?.packages.knitr || !caps?.packages.knitrVersOk) {
info("");
info(
knitrInstallationMessage(
"",
"knitr",
!!caps.packages.knitr && !caps.packages.knitrVersOk,
),
);
}
if (!!!caps?.packages.rmarkdown || !caps?.packages.rmarkdownVersOk) {
info("");
info(
knitrInstallationMessage(
"",
"rmarkdown",
!!caps?.packages.rmarkdown && !caps?.packages.rmarkdownVersOk,
),
);
}
info("");
info(
knitrInstallationMessage(
"",
"rmarkdown",
!!caps?.packages.rmarkdown && !caps?.packages.rmarkdownVersOk,
),
);
}
info("");
}
}
} catch (e) {
warning(
`Unable to gather R diagnostics: ${
e instanceof Error ? e.message : String(e)
}`,
);
}
}

Expand Down
31 changes: 31 additions & 0 deletions tests/unit/print-call-r-diagnostics.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* print-call-r-diagnostics.test.ts
*
* Tests that a failure while gathering R diagnostics (e.g. checkRBinary
* throwing) never masks the original callR error.
* See https://github.com/quarto-dev/quarto-cli/issues/14775
*
* Copyright (C) 2026 Posit Software, PBC
*/

import { unitTest } from "../test.ts";
import { assert } from "testing/asserts";
import { printCallRDiagnostics } from "../../src/execute/rmd.ts";

unitTest(
"printCallRDiagnostics - swallows a throw from R discovery",
async () => {
let threw = false;
try {
await printCallRDiagnostics(() => {
throw new Error("boom from checkRBinary");
});
} catch {
threw = true;
}
assert(
!threw,
"printCallRDiagnostics should not propagate a failure from R discovery",
);
},
);
Loading