📝 Description
There is an issue in the flag parsing lifecycle where environment variables (defined via EnvVars) for slice flags (such as StringSliceFlag, IntSliceFlag, etc.) are ignored or incorrectly overridden when multiple configuration sources (e.g., Default values, command-line arguments, or parent context settings) are present.
Specifically, when a slice flag has a defined Value (default value) and an environment variable is set, the environment variable's value is either completely ignored or fails to override the default value. According to the standard precedence rules of urfave/cli, environment variables should take precedence over default values, but command-line arguments should take precedence over environment variables. Currently, the slice flag parsing logic does not correctly merge or prioritize these sources, leading to unexpected default values being used instead of the environment variable values.
🎯 Acceptance Criteria
🛠️ Technical Specifications & Context
The issue likely resides in the flag application and parsing lifecycle, specifically within the Apply methods of the slice flag implementations or the helper functions that resolve environment variables.
Key Files to Investigate:
flag_string_slice.go (specifically StringSliceFlag.Apply)
flag_int_slice.go (specifically IntSliceFlag.Apply)
- Other slice flag files (e.g.,
flag_int64_slice.go, flag_float64_slice.go)
flag.go (where general flag application and environment variable helper functions reside)
Implementation Details:
- In
urfave/cli, flags implement the Apply(*flag.FlagSet) error interface.
- During
Apply, the flag checks if environment variables are set using helper functions (e.g., flag.go environment helpers).
- For slice flags, if an environment variable is found, its value needs to be split (usually by comma) and set on the underlying slice value.
- Ensure that if the environment variable is present, it overrides the default
Value initialization. Currently, the default value initialization might be overwriting the environment variable value, or the environment variable value is parsed but then cleared/overwritten when the flag set initializes defaults.
- Check if the flag is marked as "seen" or "set" correctly so that subsequent parsing stages know the source of the value.
🧪 Verification & Testing
Automated Tests
Add unit tests in flag_string_slice_test.go and flag_int_slice_test.go to verify the precedence:
- Test Env Var Overrides Default: Set a default value on a
StringSliceFlag, set the corresponding environment variable, run the app without CLI arguments, and assert that the slice contains only the environment variable values.
- Test CLI Overrides Env Var: Set a default value, set the environment variable, pass CLI arguments, and assert that the slice contains only the CLI argument values.
- Test Comma Separation: Set an environment variable to
foo,bar,baz and assert that the parsed slice is []string{"foo", "bar", "baz"}.
Minimal Reproducible Example for Manual Verification
Create a test harness or run the following Go code:
package main
import (
"fmt"
"os"
"github.com/urfave/cli/v2" // Adjust import path based on repository structure
)
func main() {
app := &cli.App{
Flags: []cli.Flag{
&cli.StringSliceFlag{
Name: "test-slice",
EnvVars: []string{"TEST_SLICE"},
Value: cli.NewStringSlice("default1", "default2"),
},
},
Action: func(c *cli.Context) error {
fmt.Printf("Slice values: %v\n", c.StringSlice("test-slice"))
return nil
},
}
// Scenario: Env Var is set, no CLI args passed.
// Expected Output: Slice values: [env1 env2]
// Actual Output (Bug): Slice values: [default1 default2]
os.Setenv("TEST_SLICE", "env1,env2")
if err := app.Run([]string{"app"}); err != nil {
fmt.Println(err)
}
}

This repo is using Opire - what does it mean? 👇
💵 Everyone can add rewards for this issue commenting /reward 100 (replace 100 with the amount).
🕵️♂️ If someone starts working on this issue to earn the rewards, they can comment /try to let everyone know!
🙌 And when they open the PR, they can comment /claim #1 either in the PR description or in a PR's comment.
🪙 Also, everyone can tip any user commenting /tip 20 @thaohuynh14zc (replace 20 with the amount, and @thaohuynh14zc with the user to tip).
📖 If you want to learn more, check out our documentation.
📝 Description
There is an issue in the flag parsing lifecycle where environment variables (defined via
EnvVars) for slice flags (such asStringSliceFlag,IntSliceFlag, etc.) are ignored or incorrectly overridden when multiple configuration sources (e.g.,Defaultvalues, command-line arguments, or parent context settings) are present.Specifically, when a slice flag has a defined
Value(default value) and an environment variable is set, the environment variable's value is either completely ignored or fails to override the default value. According to the standard precedence rules ofurfave/cli, environment variables should take precedence over default values, but command-line arguments should take precedence over environment variables. Currently, the slice flag parsing logic does not correctly merge or prioritize these sources, leading to unexpected default values being used instead of the environment variable values.🎯 Acceptance Criteria
EnvVarsfor all slice flags (StringSliceFlag,IntSliceFlag,Float64SliceFlag, etc.) must be correctly parsed and applied.Valuefield (lowest priority)MY_FLAG=val1,val2should result in[]string{"val1", "val2"}).EnvVarsslice, the first one that is set in the environment must be used, and subsequent ones ignored.🛠️ Technical Specifications & Context
The issue likely resides in the flag application and parsing lifecycle, specifically within the
Applymethods of the slice flag implementations or the helper functions that resolve environment variables.Key Files to Investigate:
flag_string_slice.go(specificallyStringSliceFlag.Apply)flag_int_slice.go(specificallyIntSliceFlag.Apply)flag_int64_slice.go,flag_float64_slice.go)flag.go(where general flag application and environment variable helper functions reside)Implementation Details:
urfave/cli, flags implement theApply(*flag.FlagSet) errorinterface.Apply, the flag checks if environment variables are set using helper functions (e.g.,flag.goenvironment helpers).Valueinitialization. Currently, the default value initialization might be overwriting the environment variable value, or the environment variable value is parsed but then cleared/overwritten when the flag set initializes defaults.🧪 Verification & Testing
Automated Tests
Add unit tests in
flag_string_slice_test.goandflag_int_slice_test.goto verify the precedence:StringSliceFlag, set the corresponding environment variable, run the app without CLI arguments, and assert that the slice contains only the environment variable values.foo,bar,bazand assert that the parsed slice is[]string{"foo", "bar", "baz"}.Minimal Reproducible Example for Manual Verification
Create a test harness or run the following Go code:
This repo is using Opire - what does it mean? 👇
💵 Everyone can add rewards for this issue commenting
/reward 100(replace100with the amount).🕵️♂️ If someone starts working on this issue to earn the rewards, they can comment
/tryto let everyone know!🙌 And when they open the PR, they can comment
/claim #1either in the PR description or in a PR's comment.🪙 Also, everyone can tip any user commenting
/tip 20 @thaohuynh14zc(replace20with the amount, and@thaohuynh14zcwith the user to tip).📖 If you want to learn more, check out our documentation.