larksuite/cli · error
%s takes a single "range" per sub-op, got %d entries in %q —
Error message
%s takes a single "range" per sub-op, got %d entries in %q — split them into %d sub-ops (one per range)
What it means
Each batch sub-op takes exactly one `range`. If the `range`-typed key holds an array of multiple entries, the dispatcher does not guess how to distribute them and errors, telling you how many sub-ops to create instead.
Source
Thrown at shortcuts/sheets/batch_op_dispatch.go:504
// and make that spelling's own turn read as a conflict.
canonical[target] = taken
continue
}
return fmt.Errorf("%s got both %q and %q, which are two names for the same flag, with different values — keep %q", sc, k, taken, taken) //nolint:forbidigo // intermediate error; the batch dispatcher wraps it into a typed operations validation error
}
if strings.ToLower(hv) == "ranges" && vocab["range"] && !vocab["ranges"] {
if _, taken := input["range"]; taken {
return fmt.Errorf("%s got both %q and \"range\" — keep \"range\" and drop %q", sc, k, k) //nolint:forbidigo // intermediate error; the batch dispatcher wraps it into a typed operations validation error
}
if arr, isArr := input[k].([]interface{}); isArr {
if len(arr) == 1 {
if s, isStr := arr[0].(string); isStr {
input["range"] = s
delete(input, k)
continue
}
}
return fmt.Errorf("%s takes a single \"range\" per sub-op, got %d entries in %q — split them into %d sub-ops (one per range)", sc, len(arr), k, len(arr)) //nolint:forbidigo // intermediate error; the batch dispatcher wraps it into a typed operations validation error
}
if s, isStr := input[k].(string); isStr {
input["range"] = s
delete(input, k)
continue
}
}
msg := fmt.Sprintf("unknown input key %q", k)
display := make([]string, 0, len(vocab))
for name := range vocab {
display = append(display, strings.ReplaceAll(name, "-", "_"))
}
sort.Strings(display)
if match := suggest.Closest(strings.ToLower(hv), display, 1); len(match) > 0 {
msg += fmt.Sprintf(" — did you mean %q?", match[0])
}
return fmt.Errorf("%s", msg) //nolint:forbidigo // intermediate error; the batch dispatcher wraps it into a typed operations validation error
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Split the array into multiple sub-ops, one per range, as the error message instructs.
- If only one range is needed, pass it as a plain string, not an array.
- If a single-element array was passed with non-string contents, fix the element type to a string.
Example fix
// before
{"op": "set", "range": ["A1:B2", "C1:D2"], "values": [...]}
// after
[{"op": "set", "range": "A1:B2", "values": [...]}, {"op": "set", "range": "C1:D2", "values": [...]}] Defensive patterns
Strategy: validation
Validate before calling
func expandRanges(subOp map[string]interface{}) ([]map[string]interface{}, error) {
switch v := subOp["range"].(type) {
case string:
return []map[string]interface{}{subOp}, nil
case []interface{}:
if len(v) <= 1 { return []map[string]interface{}{subOp}, nil }
out := make([]map[string]interface{}, 0, len(v))
for _, r := range v {
c := maps.Clone(subOp)
c["range"] = r
out = append(out, c)
}
return out, nil
default:
return nil, fmt.Errorf("range must be string or []string")
}
} Type guard
func isSingleRange(v interface{}) bool {
if s, ok := v.(string); ok { return s != "" }
if arr, ok := v.([]interface{}); ok { return len(arr) == 1 }
return false
} Prevention
- One range per sub-op: expand arrays into multiple sub-ops before dispatch.
- Pass ranges as plain strings, never arrays, when only one is needed.
- Validate range values with a ranges-string parser before sending.
When it happens
Trigger: Passing `"range": ["Sheet1!A1:B2", "Sheet1!C1:D2"]` (a multi-entry array) in one sub-op input of a sheets batch update. A single-element string array is auto-unwrapped; only arrays with more than one entry fail.
Common situations: Scripts that collected multiple ranges into one array and passed it to a single set/update op; migrating from APIs that accepted `ranges: [...]` per op to the one-range-per-sub-op batch format.
Related errors
- Range needs a maximum column: {range_ref}
- Range needs a maximum row: {range_ref}
- %s got conflicting values for %q under two spellings (%q and
- %s got both %q and %q — keep %q and drop the other
- %s got both %q and %q, which are two names for the same flag
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/ad63527c3909e313.
Report an issue: GitHub.