Skip to content

fix(shared): treat an empty boolean env var as unset - #8782

Closed
zhanfan-818 wants to merge 1 commit into
aws-powertools:developfrom
zhanfan-818:fix/empty-bool-env
Closed

zhanfan-818 wants to merge 1 commit into
aws-powertools:developfrom
zhanfan-818:fix/empty-bool-env

Conversation

@zhanfan-818

@zhanfan-818 zhanfan-818 commented Nov 9, 2026 •

Copy link
Copy Markdown

Issue number: closes #8765

Summary

Changes

os.getenv(name, default) only falls back to default when the variable is absent. When it is present but empty -- POWERTOOLS_DEV= in a docker-compose file, a CI job, or export POWERTOOLS_DEV=$UNSET_VAR -- it returns "", and strtobool() rejects that with ValueError: invalid truth value ''.

The same one-line pattern is at seven call sites across four modules, so this fixes them together instead of special-casing POWERTOOLS_DEV:

File Function Variable
shared/functions.py:124 powertools_dev_is_set POWERTOOLS_DEV
shared/functions.py:136 powertools_debug_is_set POWERTOOLS_DEBUG
metrics/functions.py:158 is_metrics_disabled POWERTOOLS_DEV
metrics/functions.py:159 is_metrics_disabled POWERTOOLS_METRICS_DISABLED
utilities/circuit_breaker/circuit_breaker.py:96 circuit_breaker POWERTOOLS_CIRCUIT_BREAKER_DISABLED
utilities/idempotency/idempotency.py:109 _idempotent POWERTOOLS_IDEMPOTENCY_DISABLED
utilities/idempotency/idempotency.py:219 idempotent_function POWERTOOLS_IDEMPOTENCY_DISABLED

The change is os.getenv(name, default) to os.getenv(name) or default, seven times. Strict validation is preserved: POWERTOOLS_DEV=treu still raises ValueError. Only the empty case changes, to mean "not configured" -- which is what the default was there for.

Regression tests were added for the two shared resolvers and for is_metrics_disabled.

User experience

Before, an empty value was a hard crash at import or construction time, with a message that does not say which variable is at fault:

>>> os.environ["POWERTOOLS_DEV"] = ""
>>> from aws_lambda_powertools import Logger
>>> Logger()
ValueError: invalid truth value ''

After, the same code behaves as if the variable were not set: dev mode is off, no warning is emitted, and Logger() initialises normally.

Verification

Reproduced on develop at 111f93b, before the change:

shared.powertools_dev_is_set   [POWERTOOLS_DEV=<empty>]   -> ValueError: invalid truth value ''
shared.powertools_debug_is_set [POWERTOOLS_DEBUG=<empty>] -> ValueError: invalid truth value ''
Logger()                       [POWERTOOLS_DEV=<empty>]   -> ValueError: invalid truth value ''

Confirmed the new tests fail without the fix and pass with it:

# with the fix reverted
FAILED tests/unit/test_shared_functions.py::test_powertools_bool_env_var_set_to_empty_string[POWERTOOLS_DEV-...]
FAILED tests/unit/test_shared_functions.py::test_powertools_bool_env_var_set_to_empty_string[POWERTOOLS_DEBUG-...]
FAILED tests/unit/metrics/test_functions.py::test_is_metrics_disabled_with_empty_env_var[POWERTOOLS_METRICS_DISABLED]
FAILED tests/unit/metrics/test_functions.py::test_is_metrics_disabled_with_empty_env_var[POWERTOOLS_DEV]
4 failed, 46 passed

# with the fix
50 passed in 2.82s

The circuit_breaker and idempotency sites get the identical one-line change but need a persistence store to exercise; I did not want to bolt a heavyweight harness onto this PR. Happy to add those tests if you want them here rather than in a follow-up.

AI use: the change and its tests were drafted with an AI coding assistant. I reviewed every line, reproduced the failure locally on develop, and ran the suite myself -- the output above is from my machine, not generated.


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

`os.getenv(name, default)` only falls back to `default` when the variable is
absent. When it is present but empty -- e.g. `POWERTOOLS_DEV=` in a
docker-compose file, a CI job, or `export POWERTOOLS_DEV=$UNSET_VAR` -- it
returns `""`, which `strtobool()` rejects:

    >>> os.environ["POWERTOOLS_DEV"] = ""
    >>> Logger()
    ValueError: invalid truth value ''

The same one-line pattern appears at seven call sites across four modules, so
this fixes them together instead of special-casing POWERTOOLS_DEV:

- shared/functions.py: powertools_dev_is_set, powertools_debug_is_set
- metrics/functions.py: is_metrics_disabled (POWERTOOLS_DEV, METRICS_DISABLED)
- utilities/circuit_breaker: CIRCUIT_BREAKER_DISABLED
- utilities/idempotency: IDEMPOTENCY_DISABLED (both call sites)

Using `os.getenv(name) or default` keeps the strict behaviour for genuinely
invalid values (`POWERTOOLS_DEV=treu` still raises) while letting an empty
value mean "not configured", which is what the default was for.

Tests: regression coverage for the two shared resolvers and for
is_metrics_disabled; all of them fail on the previous code and pass here.
The circuit breaker and idempotency sites are the same one-line change but
need a persistence store to exercise -- happy to add those tests if wanted.

Relates-to: aws-powertools#8765
@sonarqubecloud

sonarqubecloud Bot commented Nov 9, 2026

Copy link
Copy Markdown

@zhanfan-818

Copy link
Copy Markdown
Author

Closing this as asked -- @krishbuilds01 has the issue, and the scope in your comment is narrower than what this branch does (it touches the two idempotency.py sites that belong to #8728), so this tree would collide rather than help.

Two things worth handing over rather than throwing away, in case they save time:

  1. The tests. zhanfan-818:fix/empty-bool-env has regression tests for powertools_dev_is_set, powertools_debug_is_set and is_metrics_disabled, and I verified they fail on develop and pass with the change. They assert the silent fallback, so the expectation needs flipping to the warn-and-fallback shape -- but the setup and the parametrisation carry over. @krishbuilds01 lift whatever is useful.

  2. The call-site table is in the issue thread if it helps the resolver sweep.

And the process point is fair, no argument from me: I should have commented on the issue before opening a PR instead of alongside it. That is on me, and I will do it that way next time.

@krishbuilds01 -- good luck with it, and if you want a second pair of eyes on the resolver when it is up, ping me.

@zhanfan-818 zhanfan-818 closed this Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commons metrics size/M Denotes a PR that changes 30-99 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: POWERTOOLS_DEV set to an empty string crashes Logger initialization

1 participant