Skip to content

Improve handling of errexit option#192

Merged
frenck merged 8 commits intohassio-addons:mainfrom
lmagyar:pr-fix-errorexit
Apr 10, 2026
Merged

Improve handling of errexit option#192
frenck merged 8 commits intohassio-addons:mainfrom
lmagyar:pr-fix-errorexit

Conversation

@lmagyar
Copy link
Copy Markdown
Contributor

@lmagyar lmagyar commented Feb 1, 2026

Proposed Changes

The inherit_errexit option propagates and uses errexit in subshells in code like:

xxx=$(bashio::xxx)

This variable assignment is the default all over the library. Though it won't help, if the function runs in a condition (like 'if'), because errexit is propagated then, but ignored. (So the fixes below in config.sh and jq.sh has no effect, just makes variable usage consistent.)

To make it possible to call subshells with effective errexit even in conditions, I made the bashio::try() function. This is useful if somebody needs to add a condition around an API call that changes some configuration, because all of those "setter" functions assume errexit is effective.

Some demonstrations

errexit works as expected (only 1 error message, no need for status checks):

➜  ~ bash
~ # source /usr/lib/bashio/bashio.sh
~ # bashio::addons foo false
[21:21:11] ERROR: Requested resource /addons/foo/info was not found

The additional exit status check (in all "getter" function) saves the situation:

➜  ~ bash
~ # source /usr/lib/bashio/bashio.sh
~ # xxx=$(bashio::addons foo false)
[21:21:58] ERROR: Requested resource /addons/foo/info was not found
[21:21:58] ERROR: Failed to get addon info from Supervisor API

inherit_errexit makes errexit propagated and effective in variable assignment (default in the library):

➜  ~ bash
~ # source /usr/lib/bashio/bashio.sh
~ # shopt -s inherit_errexit
~ # xxx=$(bashio::addons foo false)
[21:22:40] ERROR: Requested resource /addons/foo/info was not found

Though inherit_errexit doesn't save the situation if there is a condition (the errexit is propageted, but ignored), we need the extra status checks (if somebody uses the library without storing the values in variables first):

➜  ~ bash
~ # source /usr/lib/bashio/bashio.sh
~ # shopt -s inherit_errexit
~ # if ! xxx=$(bashio::addons foo false); then echo ERR; fi
[21:23:52] ERROR: Requested resource /addons/foo/info was not found
[21:23:52] ERROR: Failed to get addon info from Supervisor API
ERR

And nothing saves the test functions like bashio::jq.exists()

How bashio::try helps

➜  ~ bash
~ # source /usr/lib/bashio/bashio.sh
~ # if ! bashio::supervisor.update "foo"; then echo ERR; fi
[22:10:18] ERROR: Got unexpected response from the API: No supervisor update available - 2026.01.1
~ #


~ # bashio::try bashio::supervisor.update "foo"
[22:23:41] ERROR: Got unexpected response from the API: No supervisor update available - 2026.01.1
~ # if bashio::try.failed; then echo ERR; fi
ERR
~ #

Related Issues

Summary by CodeRabbit

  • New Features

    • Added helpers to run commands and check their success/failure, simplifying command execution workflows.
  • Refactor

    • Inherited shell error behavior into subshells/command substitutions for more consistent error handling.
    • Made config and JSON reads/checks more robust by capturing results before evaluation and preventing non-critical read failures.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 1, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Enables inherit_errexit where supported, adds lib/try.sh for subshell command execution with captured exit status, and refactors config and jq helpers to capture command outputs into local variables and make read operations tolerant (|| true) in a few places.

Changes

Cohort / File(s) Summary
Bootstrap / shell options
lib/bashio, lib/bashio.sh
Enables shopt -s inherit_errexit (errors suppressed) so errexit is inherited into subshells/command substitutions; lib/try.sh is sourced from bootstrap.
New try utilities
lib/try.sh
Adds bashio::try, bashio::try.succeeded, bashio::try.failed and global __BASHIO_TRY_EXIT_STATUS; runs commands in a subshell with errexit enabled and records exit status.
Config adjustments
lib/config.sh
bashio::config() here-doc read made tolerant (`
JQ helpers refactor
lib/jq.sh
bashio::jq.exists, bashio::jq.has_value, bashio::jq.is now assign outputs to a local value and perform checks against that captured value (conditionals updated).
Services read robustness
lib/services.sh
Here-doc read for JSON query now appends `

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant TryLib as bashio::try
    participant Subshell
    participant State as __BASHIO_TRY_EXIT_STATUS

    Caller->>TryLib: bashio::try "<command>"
    TryLib->>Subshell: run command (errexit enabled inside)
    Subshell-->>TryLib: exit status (0 / non‑0)
    TryLib->>State: store exit status
    TryLib-->>Caller: return (outer errexit preserved)

    Caller->>TryLib: bashio::try.succeeded / bashio::try.failed
    TryLib->>State: read stored exit status
    TryLib-->>Caller: return OK / NOK based on stored status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

bugfix

Poem

🐰 I hopped into code with care,
I set errexit to share,
A tiny try‑shell, neat and bright,
Captures exits out of sight,
🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: improving errexit option handling through inherit_errexit configuration and the new bashio::try utility.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/bashio`:
- Line 13: The direct call shopt -s inherit_errexit should be guarded for Bash <
4.4; update the code around the shopt invocation to first check BASH_VERSINFO
(major/minor) and only run shopt -s inherit_errexit when Bash version >= 4.4
(otherwise skip it) so the script won’t exit under set -e on older shells;
locate the existing shopt -s inherit_errexit line and replace it with a
version-check conditional that uses BASH_VERSINFO to decide whether to enable
inherit_errexit.

Comment thread lib/bashio Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/jq.sh`:
- Around line 67-72: The conditional in lib/jq.sh has a duplicated `||` causing
a syntax error; fix the if statement that evaluates the result of bashio::jq and
bashio::var.has_value by removing the extra `||` so it reads as a single logical
OR between the two checks (i.e., ensure the condition is: if !
value=$(bashio::jq ... ) || ! bashio::var.has_value "${value}" then ...),
keeping the existing variables and calls (value, bashio::jq,
bashio::var.has_value, and returning __BASHIO_EXIT_NOK) intact.

Comment thread lib/jq.sh
@lmagyar
Copy link
Copy Markdown
Contributor Author

lmagyar commented Feb 3, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 3, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 6, 2026

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days. Thank you for your contributions.

@github-actions github-actions bot added the stale There has not been activity on this issue or PR for quite some time. label Mar 6, 2026
@lmagyar
Copy link
Copy Markdown
Contributor Author

lmagyar commented Mar 8, 2026

not stale

@github-actions github-actions bot removed the stale There has not been activity on this issue or PR for quite some time. label Mar 9, 2026
@frenck frenck added the new-feature New features or options. label Apr 7, 2026
@frenck frenck requested a review from Copilot April 7, 2026 13:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves Bashio’s error-handling semantics around errexit, especially for command substitutions and conditionals, by enabling inherit_errexit and introducing a bashio::try helper to run commands in an errexit-effective subshell while capturing the exit status.

Changes:

  • Enable inherit_errexit in the main entrypoints to make errexit propagate into command substitutions.
  • Add lib/try.sh implementing bashio::try, bashio::try.succeeded, and bashio::try.failed.
  • Make jq/config/service query construction and jq checks more robust in conditional contexts by avoiding fragile command substitutions and making read -d '' non-fatal.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
lib/try.sh Adds a helper for running commands in an errexit-effective subshell and recording the exit status for later inspection.
lib/bashio.sh Enables inherit_errexit and sources the new try module.
lib/bashio Enables inherit_errexit in the wrapper entrypoint as well.
lib/jq.sh Refactors jq helper predicates to capture jq output and treat jq failures as predicate failures.
lib/config.sh Makes heredoc read -d '' non-fatal under errexit and refactors config.exists to avoid inline command substitution.
lib/services.sh Makes heredoc read -d '' non-fatal under errexit.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/bashio.sh Outdated
Comment thread lib/bashio Outdated
Comment thread lib/try.sh
Comment thread lib/try.sh
Comment thread lib/try.sh Outdated
Comment thread lib/try.sh Outdated
Comment thread lib/config.sh
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Comment thread lib/bashio Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
lib/try.sh (1)

32-37: Preserve caller errexit state instead of forcing it on exit.

At Line 36, set -e is always re-enabled. If a caller intentionally had errexit disabled, this function mutates outer shell behavior after return. Prefer saving and restoring prior state.

♻️ Proposed change
 function bashio::try {
+    local __bashio_try_errexit_was_set=0
+    [[ $- == *e* ]] && __bashio_try_errexit_was_set=1
     set +e
     (set -e; "$@")
     __BASHIO_TRY_EXIT_STATUS=$?
-    set -e
+    if ((__bashio_try_errexit_was_set)); then
+        set -e
+    else
+        set +e
+    fi
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/try.sh` around lines 32 - 37, The function bashio::try currently
unconditionally runs "set -e" on exit which mutates the caller's errexit state;
fix by capturing the caller's errexit state at the start of bashio::try (e.g.,
test whether the "e" flag is present in $- or use set -o) into a local variable,
run the subshell and set __BASHIO_TRY_EXIT_STATUS as before, and then restore
the original errexit state (re-enable with "set -e" only if it was originally
enabled, otherwise run "set +e") so the caller's shell options are preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/try.sh`:
- Around line 32-37: The function bashio::try currently unconditionally runs
"set -e" on exit which mutates the caller's errexit state; fix by capturing the
caller's errexit state at the start of bashio::try (e.g., test whether the "e"
flag is present in $- or use set -o) into a local variable, run the subshell and
set __BASHIO_TRY_EXIT_STATUS as before, and then restore the original errexit
state (re-enable with "set -e" only if it was originally enabled, otherwise run
"set +e") so the caller's shell options are preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 30c67d87-e865-40bf-93ff-5698ad1390e8

📥 Commits

Reviewing files that changed from the base of the PR and between ceeef16 and 684ea67.

📒 Files selected for processing (3)
  • lib/bashio
  • lib/bashio.sh
  • lib/try.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/bashio
  • lib/bashio.sh

Copy link
Copy Markdown
Member

@frenck frenck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @lmagyar 👍

../Frenck

                       

Blogging my personal ramblings at frenck.dev

@frenck frenck merged commit 805791e into hassio-addons:main Apr 10, 2026
4 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Apr 12, 2026
@lmagyar lmagyar deleted the pr-fix-errorexit branch April 13, 2026 09:04
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

new-feature New features or options.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants