larksuite/cli · error

ValueSources must include flag

Error message

ValueSources must include flag

What it means

When ValueSources is non-empty, the flag source is mandatory: multi-source inputs are defined as 'flag first, optionally supplemented by file/stdin'. validateInputCLI rejects a list like [file] or [stdin] alone because a field whose value never comes from the command line flag breaks the CLI contract for primary inputs.

Solutions

  1. Add "flag" as the first entry of ValueSources
  2. If the field must not be a CLI flag, do not use ValueSources - hide the flag (CLI.Hidden) instead
  3. Remove ValueSources entirely to fall back to the default flag-only behavior

Example fix

// before
ValueSources: []string{"file", "stdin"}
// after
ValueSources: []string{"flag", "file", "stdin"}
Defensive patterns

Strategy: validation

Validate before calling

func hasFlagSource(srcs []string) bool {
	for _, s := range srcs {
		if s == "flag" {
			return true
		}
	}
	return false
}
// require len(srcs) == 0 || hasFlagSource(srcs)

Try / catch

if err := compileInput(...); err != nil {
	if strings.Contains(err.Error(), "must include flag") {
		// prepend "flag" to ValueSources
	}
	return err
}

Prevention

When it happens

Trigger: Declaring ValueSources without "flag", e.g. ValueSources: []string{"file"} or []string{"file","stdin"}, intending to read the value only from a file or stdin. Raised by compileInput during shortcut compilation.

Common situations: Assuming a field can be file-only or stdin-only; building a 'silent' input that is never shown as a flag; misunderstanding that ValueSources is additive to flag rather than a replacement.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/afbcc4e6e28a856f. Report an issue: GitHub.

Appendix: source

Thrown at shortcuts/common/typed_compile_args.go:293

	}
	if field.defaultValue.Set {
		if err := valueAssignableTo(field.defaultValue.Value, field.valueType); err != nil {
			return fmt.Errorf("default: %w", err)
		}
	}
	seenSources := make(map[typedValueSource]struct{})
	for _, source := range field.cli.ValueSources {
		if source != typedSourceFlag && source != typedSourceFile && source != typedSourceStdin {
			return fmt.Errorf("unknown value source %q", source)
		}
		if _, duplicate := seenSources[source]; duplicate {
			return fmt.Errorf("duplicate value source %q", source)
		}
		seenSources[source] = struct{}{}
	}
	if len(field.cli.ValueSources) > 0 {
		if _, ok := seenSources[typedSourceFlag]; !ok {
			return fmt.Errorf("ValueSources must include flag")
		}
		if (len(seenSources) > 1) && indirectKind(field.valueType) != reflect.String && field.cli.Encoding != typedEncodingJSON {
			return fmt.Errorf("file/stdin sources require string input or encoding=json")
		}
	}
	kind := indirectKind(field.valueType)
	if kind == reflect.Slice || kind == reflect.Array || kind == reflect.Struct || kind == reflect.Map || kind == reflect.Interface {
		if field.cli.Encoding == "" {
			return fmt.Errorf("%s input must explicitly declare CLI encoding", kind)
		}
	}
	switch field.cli.Encoding {
	case "":
		if kind == reflect.Slice || kind == reflect.Array || kind == reflect.Struct || kind == reflect.Map || kind == reflect.Interface {
			return fmt.Errorf("complex input requires encoding")
		}
	case typedEncodingRepeated:
		if kind != reflect.Slice && kind != reflect.Array {

View on GitHub (pinned to 7fd6ef3c07)