larksuite/cli · error

Args field %s flag --%s duplicates %s

Error message

Args field %s flag --%s duplicates %s

What it means

After collecting struct fields, compileInput records every compiled flag name (and alias) in allNames and rejects any collision. This error means a struct Args field produced a flag name that another field (or its alias) already claimed; 'previous' names what claimed it first.

Source

Thrown at shortcuts/common/typed_compile_args.go:48

		if !flagNamePattern.MatchString(supplement.Name) {
			return nil, nil, fmt.Errorf("Input.Fields[%d].Name %q is not a canonical flag name", i, supplement.Name)
		}
		if _, exists := supplements[supplement.Name]; exists {
			return nil, nil, fmt.Errorf("Input.Fields contains duplicate flag %q", supplement.Name)
		}
		supplements[supplement.Name] = supplement
	}
	var fields []compiledInputField
	seenGo := make(map[string]struct{})
	if err := collectArgFields(argsType, nil, false, &fields, seenGo, supplements); err != nil {
		return nil, nil, err
	}
	fieldByName := make(map[string]int, len(fields))
	allNames := make(map[string]string, len(fields))
	for i := range fields {
		field := &fields[i]
		if previous, exists := allNames[field.name]; exists {
			return nil, nil, fmt.Errorf("Args field %s flag --%s duplicates %s", field.goName, field.name, previous)
		}
		allNames[field.name] = "--" + field.name
		fieldByName[field.name] = i
		supplement, hasSupplement := supplements[field.name]
		if hasSupplement {
			if err := mergeInputSupplement(field, supplement); err != nil {
				return nil, nil, fmt.Errorf("Args field %s (--%s): %w", field.goName, field.name, err)
			}
			delete(supplements, field.name)
		}
		if field.description == "" {
			return nil, nil, fmt.Errorf("Args field %s (--%s): description is required via doc or InputField.Description", field.goName, field.name)
		}
		if err := validateInputCLI(field); err != nil {
			return nil, nil, fmt.Errorf("Args field %s (--%s): %w", field.goName, field.name, err)
		}
		for _, alias := range field.cli.Aliases {
			if previous, exists := allNames[alias.Name]; exists {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Rename one field's flag tag so each flag is unique.
  2. Remove the colliding alias from field.cli.Aliases.
  3. Flatten or restructure nested inline structs that produce overlapping flag names.

Example fix

// before
type Args struct {
  Source string `flag:"name"`
  Target string `flag:"name"`
}
// after
type Args struct {
  Source string `flag:"source-name"`
  Target string `flag:"target-name"`
}
Defensive patterns

Strategy: validation

Validate before calling

func noFlagCollisions(args any) error {
  names := map[string]string{}
  t := reflect.TypeOf(args)
  for i := 0; i < t.NumField(); i++ {
    f := t.Field(i)
    if n, ok := f.Tag.Lookup("flag"); ok {
      if prev, dup := names[n]; dup {
        return fmt.Errorf("flag --%s declared by both %s and %s", n, prev, f.Name)
      }
      names[n] = f.Name
    }
  }
  return nil
}

Prevention

When it happens

Trigger: Two struct fields mapped to the same flag (e.g. via identical flag tags or nested inline structs that both yield "name"), or a supplement alias colliding with an earlier flag name, during compileInput.

Common situations: Embedding/Inlining two structs that each define a "status" field; a json-tag-derived flag colliding with an explicit flag tag; an alias on one field equal to another field's primary flag.

Related errors


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