fix(console): write app command loading errors to stderr - #297
Open
printminion-co wants to merge 1 commit into
Open
fix(console): write app command loading errors to stderr#297printminion-co wants to merge 1 commit into
printminion-co wants to merge 1 commit into
Conversation
printminion-co
force-pushed
the
mk/fix/occ-console-command-load-error-to-stderr
branch
2 times, most recently
from
July 31, 2026 08:14
1b5de99 to
281a0cc
Compare
When an app fails to load its commands from info.xml, the error was
written to stdout, while every other diagnostic in loadCommands() uses
$output->getErrorOutput(). The command itself then runs normally and
exits 0, so the message silently corrupts machine-readable output:
$ ./occ app:list --output=json
Connection refused
{"enabled":{...},"disabled":{...}}
$ echo $?
0
Anything piping `occ <cmd> --output=json` into a JSON parser breaks, with
no non-zero exit code to detect it by.
Observed with notify_push on a setup that has the phpredis extension
loaded but no Redis configured: RedisFactory::isAvailable() only checks
whether the extension is loaded, so constructing the app's console
commands ends up calling pconnect() and throws RedisException.
--no-warnings is not a workaround for this, as it sets VERBOSITY_QUIET
and suppresses the payload too.
Route the message to the error output instead. It is still reported via
logger->error() exactly as before.
Assisted-by: ClaudeCode:claude-opus-5
Signed-off-by: Misha M.-Kupriyanov <kupriyanov@strato.de>
printminion-co
force-pushed
the
mk/fix/occ-console-command-load-error-to-stderr
branch
from
July 31, 2026 08:15
281a0cc to
9345ce5
Compare
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
occ <cmd> --output=jsoncan emit a non-JSON error line on stdout ahead of the JSON payload, while still exiting0.Anything that pipes
occ ... --output=jsoninto a JSON parser breaks, and there is no non-zero exit code to detect it by. In our case this silently brokedev-install.sh: the IONOS setup scripts doocc app:list --output json | jq ...,jqfails to parse, the app list comes back empty, and the scripts then treat every app as disabled.Cause
In
OC\Console\Application::loadCommands(), thecatch (\Throwable $e)aroundloadCommandsFromInfoXml()reports the failure with$output->writeln()— stdout — whereas every other diagnostic in the same method already uses$output->getErrorOutput()(insufficient memory limit, "Nextcloud is not installed", "requires upgrade", maintenance-mode notices). The command itself then runs and succeeds, so the message is pure stdout contamination.$outputis typedConsoleOutputInterface, sogetErrorOutput()is guaranteed by the signature.How we hit it
notify_pushon a setup that has the phpredis extension loaded but no Redis configured.RedisFactory::isAvailable()only checksextension_loaded('redis'), not whether aredisconfig block exists, soPushRedisFactory::getRedis()takes the Redis branch, falls back to127.0.0.1:6379and throwsRedisException: Connection refusedwhile the app's console commands are being constructed. Since notify_push declares 5 commands ininfo.xml, this happened on everyoccinvocation.The app-side behaviour is arguably its own issue, but the console bootstrap should not corrupt stdout regardless of which app fails to load.
--no-warningsis not a workaround: it setsVERBOSITY_QUIET, which suppresses the JSON payload too.TODO
Upstream tracking — this fix is vanilla and IONOS-agnostic, so it was also submitted to
vanilla Nextcloud. Ideally it lands upstream and reaches us via the next rebase, making the
fork-side carry temporary.
nextcloud/server:mastermastervia rebase — drop the fork-side carry thenstable33,stable34,stable35ionos-dev-v33(single occurrence there, line 103)Changes
Two call sites (the
app_apimaintenance-mode block and the regular installed-apps loop) now write to$output->getErrorOutput(). Thelogger->error()calls are unchanged, so the failure is still logged.Verification
./occ app:list --output=jsonnow writes only JSON to stdout; the error appears on stderr and is still recorded innextcloud.logwith its full stack trace.Branched off
master(vanilla) and free of IONOS specifics, so it can be submitted upstream tonextcloud/serveras-is.Checklist
OC\Console\Applicationionos-dev-v33is a separate stepAI (if applicable)