Fix compile error propagation: 'failure' instead of HTTP 500
Build and Deploy Verso / deploy (push) Successful in 10m37s
Build and Deploy Verso / deploy (push) Successful in 10m37s
LocalCommandRunner: attach captured stdout to the error object when exit code is 1, so callers can read Quarto's output even on failure. QuartoRunner: stop propagating plain 'exited' errors from Quarto up to CompileManager. A Quarto exit-code-1 is a compile failure, not a server error — CLSI already detects failure by the absence of output.pdf and returns status='failure' (HTTP 200). Previously it fell through to the generic error handler (HTTP 500), which caused the frontend to show "Server Error" instead of the log panel. Only true process-level errors (terminated, timedout) are propagated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -89,9 +89,10 @@ export default CommandRunner = {
|
|||||||
err.terminated = true
|
err.terminated = true
|
||||||
return callback(err)
|
return callback(err)
|
||||||
} else if (code === 1) {
|
} else if (code === 1) {
|
||||||
// exit status from chktex
|
// exit status from chktex (and any compiler that exits 1 on failure)
|
||||||
err = new Error('exited')
|
err = new Error('exited')
|
||||||
err.code = code
|
err.code = code
|
||||||
|
err.stdout = stdout // preserve captured output for callers
|
||||||
return callback(err)
|
return callback(err)
|
||||||
} else {
|
} else {
|
||||||
return callback(null, { stdout, exitCode: code })
|
return callback(null, { stdout, exitCode: code })
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ function runQuarto(compileName, options, callback) {
|
|||||||
const { directory, mainFile, image, environment, compileGroup } = options
|
const { directory, mainFile, image, environment, compileGroup } = options
|
||||||
const timeout = options.timeout || 60000
|
const timeout = options.timeout || 60000
|
||||||
|
|
||||||
logger.debug({ directory, timeout, mainFile, compileGroup }, 'starting quarto compile')
|
logger.debug(
|
||||||
|
{ directory, timeout, mainFile, compileGroup },
|
||||||
|
'starting quarto compile'
|
||||||
|
)
|
||||||
|
|
||||||
const command = _buildQuartoCommand(mainFile)
|
const command = _buildQuartoCommand(mainFile)
|
||||||
|
|
||||||
@@ -26,22 +29,31 @@ function runQuarto(compileName, options, callback) {
|
|||||||
null,
|
null,
|
||||||
function (error, output) {
|
function (error, output) {
|
||||||
delete ProcessTable[compileName]
|
delete ProcessTable[compileName]
|
||||||
if (error) {
|
|
||||||
// Still try to write whatever output we captured before the error
|
// Propagate real process-level errors (killed, timed out) but NOT
|
||||||
_writeLogOutput(compileName, directory, output, () => callback(error))
|
// ordinary non-zero exit codes from Quarto itself. A Quarto compile
|
||||||
return
|
// failure (exit code 1) is not a server error — the absence of
|
||||||
|
// output.pdf is sufficient for CompileController to return 'failure'.
|
||||||
|
if (error && (error.terminated || error.timedout)) {
|
||||||
|
return callback(error)
|
||||||
}
|
}
|
||||||
_writeLogOutput(compileName, directory, output, () => callback(null, output))
|
|
||||||
|
// On exit-code-1 errors LocalCommandRunner attaches stdout to the
|
||||||
|
// error object; merge it so _writeLogOutput can persist it.
|
||||||
|
const combined = output || (error ? { stdout: error.stdout || '' } : null)
|
||||||
|
_writeLogOutput(compileName, directory, combined, () =>
|
||||||
|
callback(null, combined)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function _buildQuartoCommand(mainFile) {
|
function _buildQuartoCommand(mainFile) {
|
||||||
// Run through a POSIX shell so we can merge stderr into stdout.
|
// Run through a POSIX shell so stderr is merged into stdout (2>&1).
|
||||||
// Quarto writes all progress and error messages to stderr; without this
|
// Quarto writes all progress and error messages to stderr; without this
|
||||||
// merge the UI would show nothing in the log panel on failure.
|
// the log panel would be empty on failure.
|
||||||
// LocalCommandRunner replaces $COMPILE_DIR before the shell sees the string,
|
// LocalCommandRunner replaces $COMPILE_DIR before the shell sees the
|
||||||
// so the substitution is safe and no shell variable expansion occurs.
|
// string, so no shell variable expansion occurs for that token.
|
||||||
const quartoArgs = [
|
const quartoArgs = [
|
||||||
'quarto',
|
'quarto',
|
||||||
'render',
|
'render',
|
||||||
|
|||||||
Reference in New Issue
Block a user