-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Description
Bug report criteria
- This bug report is not security related, security issues should be disclosed privately via [email protected].
- This is not a support request or question, support requests or questions should be raised in the etcd discussion forums.
- You have read the etcd bug reporting guidelines.
- Existing open issues along with etcd frequently asked questions have been checked and this is not a duplicate.
What happened?
When running make test or make test-unit without setting the TESTCASE environment variable, the test script fails with:
PASSES="unit" ./scripts/test.sh
Running with --race
Starting at: Wed Jan 14 09:47:58 CST 2026
'unit' started at Wed Jan 14 09:47:58 CST 2026
./scripts/test.sh: line 130: RUN_ARG[@]: unbound variable
make: *** [test-unit] Error 1
This prevents developers from running tests locally on macOS (which uses bash 3.2 by default).
What did you expect to happen?
The test script should run successfully without requiring the TESTCASE environment variable to be set. According to the script's documentation, TESTCASE is optional and should only be used when running specific test cases.
How can we reproduce it (as minimally and precisely as possible)?
- Clone the etcd repository
- Ensure you have bash 3.2 (macOS default) or any bash version that strictly enforces
set -o nounset - Run
make test-unitormake testwithout settingTESTCASE - The script will fail with the "unbound variable" error
Minimal reproduction:
# On macOS with default bash 3.2
cd /path/to/etcd
make test-unitExpected: Tests run successfully
Actual: Script fails with "unbound variable" error
Anything else we need to know?
Environment Information
- OS: macOS (darwin 26.2.0)
- Bash version: GNU bash, version 3.2.57(1)-release (arm64-apple-darwin25)
- etcd version: Current main branch
- Go version: (not relevant for this issue)
Root Cause Analysis
The issue occurs because:
- The script uses
set -o nounset(line 55) for strict error checking - When
TESTCASEis not set,RUN_ARGis initialized as an empty array:RUN_ARG=() - The script then tries to expand the empty array:
"${RUN_ARG[@]}" - In bash 3.2 (and some other versions), expanding an empty array under
set -o nounsettriggers an "unbound variable" error
The problematic code is in scripts/test.sh:
RUN_ARG=()
if [ -n "${TESTCASE:-}" ]; then
RUN_ARG=("-run=${TESTCASE}")
fi
# Later in functions like unit_pass, integration_pass, etc.:
"${RUN_ARG[@]}" # This fails when RUN_ARG is emptyImpact
- Affected users: Developers on macOS or systems with bash 3.2
- Severity: Medium - blocks local development and testing
- Workaround: Set
TESTCASE=""(empty string) or upgrade bash, but this shouldn't be necessary
Proposed Solutions
Solution 1: Use string instead of array (Recommended)
Change RUN_ARG from an array to a string. This is the simplest and most elegant solution:
RUN_ARG=""
if [ -n "${TESTCASE:-}" ]; then
RUN_ARG="-run=${TESTCASE}"
fi
# Later in functions:
$RUN_ARG # Empty string expands to nothing, no errorThis approach:
- ✅ Works with bash 3.2+ (backward compatible)
- ✅ Maintains
set -o nounsetstrict checking - ✅ Doesn't change existing functionality
- ✅ Makes
TESTCASEtruly optional as documented - ✅ No external dependencies or version requirements
- ✅ Minimal code changes (just change array to string)
- ✅ No conditional checks needed in each function
Cons:
- Requires changing array syntax to string syntax (but simpler overall)
Solution 2: Upgrade bash version (Alternative)
Require developers to use bash 4.4+ where empty array expansion works correctly under set -o nounset.
brew install bash
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
Pros:
- ✅ No code changes needed
- ✅ Uses more modern bash features
Cons:
- ❌ Breaks compatibility with macOS default bash (3.2)
- ❌ Requires all contributors to upgrade bash
- ❌ May exclude developers who can't easily upgrade
- ❌ Goes against the project's compatibility goals (using
#!/usr/bin/env bashsuggests compatibility is important) - ❌ Not a practical solution for a widely-used open source project
Additional Context
- This is a development tool issue, not an etcd server bug
- The script's documentation indicates
TESTCASEshould be optional - CI/CD environments may use newer bash versions where this doesn't fail, but local development environments (especially macOS) are affected
- Similar compatibility issues have been addressed in other parts of the codebase
Related
This issue affects the following test functions in scripts/test.sh:
unit_passintegration_extraintegration_passe2e_passrobustness_passgrpcproxy_integration_passgrpcproxy_e2e_pass
Request for good first issue label:
This issue seems suitable for a good first issue label because:
- ✅ No Barrier to Entry - Only requires basic bash knowledge
- ✅ Solution Explained - Solution clearly described above
- ✅ Identifies Relevant Code - Code location clearly identified
- ✅ Ready to Test - Can be tested with
make test-unit - ✅ Low Risk - Simple syntax change
Etcd version (please run commands below)
not relevant for this issue
Etcd configuration (command line flags or environment variables)
not relevant for this issue
Etcd debug information (please run commands below, feel free to obfuscate the IP address or FQDN in the output)
not relevant for this issue
Relevant log output
PASSES="unit" ./scripts/test.sh
Running with --race
Starting at: Wed Jan 14 09:47:58 CST 2026
'unit' started at Wed Jan 14 09:47:58 CST 2026
./scripts/test.sh: line 130: RUN_ARG[@]: unbound variable
make: *** [test-unit] Error 1