Version
2026.07.02
Unraid Version
7.3.1
Bug Description
Summary
compose.sh always returns exit code 0 for the up action (and likely down/stop/pull), regardless of whether the underlying docker compose command actually succeeded. As a result, the autostart handler (event/docker_started) logs "Stack X started successfully" even when the stack failed to start, and the real error output from docker compose is discarded instead of being logged.
Root cause
In compose.sh, the up) case branch does roughly:
"${compose_base[@]}" -p "$name" up "${cmd_args[@]}" -d
exit_code=$?
if [ $exit_code -eq 0 ]; then
...
echo "✓ Stack $name started successfully"
else
save_result "failed" $exit_code "up"
log_msg "ERROR" "Failed to start stack $name (exit code: $exit_code)"
echo ""
echo "✗ Stack $name failed to start (exit code: $exit_code)"
fi
;;
There is no explicit exit $exit_code after this block, or anywhere else in the script for this code path. In bash, a script with no explicit exit returns the exit status of the last command it ran — and in both branches that's an echo, which always returns 0. So compose.sh itself exits 0 even on the failure path.
Impact
event/docker_started uses the wrapper's own exit code to decide success/failure:
output=$(timeout "$STARTUP_TIMEOUT" "${cmd_args[@]}" 2>&1)
exit_code=$?
if [ $exit_code -eq 0 ]; then
log "Stack $stack_name started successfully in ${duration}s"
return 0
...
Because compose.sh always returns 0, this success branch runs even when docker compose up actually failed. Two consequences:
- The log falsely reports success for stacks that never started.
- The branch that logs the last 5 lines of
docker compose output for debugging never executes, so the real failure reason is silently thrown away.
Expected Behavior
Errors should be logged and the script should so stack that did not start as failed not as successful.
Suggested fix
Capture the real exit code and propagate it explicitly instead of relying on the last command's status — e.g. exit "$exit_code" at the end of each case branch that can fail, or at minimum at the end of the script.
Workaround used
Manually patched compose.sh locally by appending an explicit exit after the closing esac:
printf '\nexit "${exit_code:-0}"\n' >> compose.sh
This surfaced the real errors for two stacks that had been silently logged as "started successfully":
audiobookshelf: open /boot/config/plugins/compose.manager/projects/audiobookshelf/compose.override.yaml: no such file or directory
photoprism: Error response from daemon: failed to set up container networking: network <id> not found
Steps to Reproduce
Boot a system with a stack whose docker compose up fails (e.g. a missing override file, a stale network reference). Syslog shows both lines, back to back, for the same stack:
[ERROR] [compose] Failed to start stack <name> (exit code: 1)
[INFO] [autostart] Stack <name> started successfully in 0s
Relevant Logs
Compose
Additional Context
No response
Version
2026.07.02
Unraid Version
7.3.1
Bug Description
Summary
compose.shalways returns exit code0for theupaction (and likelydown/stop/pull), regardless of whether the underlyingdocker composecommand actually succeeded. As a result, the autostart handler (event/docker_started) logs "Stack X started successfully" even when the stack failed to start, and the real error output fromdocker composeis discarded instead of being logged.Root cause
In
compose.sh, theup)case branch does roughly:There is no explicit
exit $exit_codeafter this block, or anywhere else in the script for this code path. In bash, a script with no explicitexitreturns the exit status of the last command it ran — and in both branches that's anecho, which always returns0. Socompose.shitself exits0even on the failure path.Impact
event/docker_starteduses the wrapper's own exit code to decide success/failure:Because
compose.shalways returns0, this success branch runs even whendocker compose upactually failed. Two consequences:docker composeoutput for debugging never executes, so the real failure reason is silently thrown away.Expected Behavior
Errors should be logged and the script should so stack that did not start as failed not as successful.
Suggested fix
Capture the real exit code and propagate it explicitly instead of relying on the last command's status — e.g.
exit "$exit_code"at the end of each case branch that can fail, or at minimum at the end of the script.Workaround used
Manually patched
compose.shlocally by appending an explicit exit after the closingesac:This surfaced the real errors for two stacks that had been silently logged as "started successfully":
Steps to Reproduce
Boot a system with a stack whose
docker compose upfails (e.g. a missing override file, a stale network reference). Syslog shows both lines, back to back, for the same stack:Relevant Logs
Compose
Additional Context
No response