larksuite/cli · error

file/stdin sources require string input or encoding=json

Error message

file/stdin sources require string input or encoding=json

What it means

file/stdin values arrive as raw text, so a field combining multiple sources must either have a string value type or use encoding=json to parse the text into a complex value. validateInputCLI enforces this when len(seenSources) > 1: if the indirect kind is not reflect.String and CLI.Encoding is not json, the text cannot be safely converted.

Source

Thrown at shortcuts/common/typed_compile_args.go:296

			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 {
			return fmt.Errorf("encoding repeated requires an array or slice")
		}
		if indirectType(field.valueType).Elem().Kind() != reflect.String {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Set Encoding: "json" in the cli tag so file/stdin text is parsed as JSON into the target type
  2. Change the field's value type to string if raw text is what you want
  3. Drop the file/stdin sources if the typed non-string field should only come from a flag

Example fix

// before
ValueSources: []string{"flag", "file"} // int field, no encoding
// after
ValueSources: []string{"flag", "file"}
Encoding: "json" // or change the field to a string type
Defensive patterns

Strategy: validation

Validate before calling

func multiSourceOK(kind reflect.Kind, enc string) bool {
	return kind == reflect.String || enc == "json"
}
// check before enabling file/stdin sources on a non-string field

Try / catch

if err := compileInput(...); err != nil {
	if strings.Contains(err.Error(), "file/stdin sources require") {
		// set encoding=json or change the type to string
	}
	return err
}

Prevention

When it happens

Trigger: Declaring ValueSources with more than one source (e.g. [flag, file]) on a field whose valueType is int, bool, a slice, or a struct while leaving encoding unset or non-json. Raised by compileInput during shortcut compilation.

Common situations: Adding a file source to an integer or boolean input assuming the raw text will be coerced; adding file/stdin to a slice field without setting encoding=json; mixing an @file-style convenience with typed non-string inputs.

Related errors


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