cilium/cilium · warning
unexpected RHS expression length
Error message
unexpected RHS expression length
What it means
getEllipsisRHSExpansion requires the identifier's assigning statement to have exactly one RHS expression (i.e. a plain `x := expr`). Multi-value or tuple assignments such as `a, b := f()` have len(Rhs) != 1, so this error is returned. The analyzer cannot unambiguously attribute which RHS produced the spread slice.
Source
Thrown at tools/metricslint/pkg/analyzer/analyzer.go:54
func getEllipsisRHSExpansion(expr ast.Expr) (*ast.CompositeLit, error) {
var ident *ast.Ident
sel, ok := expr.(*ast.SelectorExpr)
if ok {
ident, ok = sel.X.(*ast.Ident)
} else {
ident, ok = expr.(*ast.Ident)
}
if !ok {
return nil, fmt.Errorf("unknown identifier")
}
inlineAssignment, ok := ident.Obj.Decl.(*ast.AssignStmt)
if !ok {
return nil, fmt.Errorf("expected assignment statement")
}
if len(inlineAssignment.Rhs) != 1 {
return nil, fmt.Errorf("unexpected RHS expression length")
}
slice, ok := inlineAssignment.Rhs[0].(*ast.CompositeLit)
if !ok {
return nil, fmt.Errorf("expected composite literal")
}
return slice, nil
}
func countArgs(call *ast.CallExpr) (int, error) {
if call.Ellipsis == token.NoPos {
// Simple path: Args are directly specified to the method.
return len(call.Args), nil
}
if len(call.Args) != 1 {
return 0, fmt.Errorf("unsupported ellipsis expression")
}
if warnDeprecated {View on GitHub (pinned to ac7b90affa)
Solutions
- Split the declaration so the slice gets its own single-value assignment: `vals := getVals()` rather than destructuring a multi-return.
- Reassign into a fresh single-value variable before the variadic call: `ks := keys; c.WithLabels(ks...)` still fails — instead build via `ks := []string{...}`.
- Suppress/ignore the analyzer report if the code is valid Go.
- Improve the tool to use go/types so tuple assignments resolve correctly.
Example fix
// before // keys, extra := parseLabels(cfg) // counter.WithLabels(keys...) // after // all := parseLabels(cfg) // keys := all.keys // counter.WithLabels(keys...)
Defensive patterns
Strategy: validation
Validate before calling
// Give the spread slice a single-RHS declaration:
// BAD: keys, extra := parseLabels(cfg)
// GOOD:
// parsed := parseLabels(cfg)
// keys := parsed.keys
func hasSingleRHS(as *ast.AssignStmt) bool { return len(as.Rhs) == 1 } Type guard
func isSingleValueAssign(ident *ast.Ident) bool {
as, ok := ident.Obj.Decl.(*ast.AssignStmt)
return ok && len(as.Rhs) == 1 && len(as.Lhs) == 1
} Try / catch
count, err := countArgs(call)
if err != nil && strings.Contains(err.Error(), "unexpected RHS expression length") {
log.Printf("multi-value assignment not supported by metricslint; skipping")
return
} Prevention
- Avoid destructuring multi-return functions into the variable later spread with '...'.
- Extract the slice into its own single-value assignment before the variadic call.
- Keep tuple-assignment results out of metric With* call sites.
- Review refactors that convert single := declarations into comma-ok or multi-return forms.
When it happens
Trigger: Spread argument was declared in a multi-value assignment, e.g. `keys, vals := splitLabels()` then `c.WithLabels(keys...)`; also `sl, err := build()` followed by `WithLabels(sl...)`.
Common situations: Metric labels derived from a function returning two values; comma-ok type assertions (`v, ok := m["k"]`) used to build the slice.
Related errors
- unknown identifier
- expected assignment statement
- expected composite literal
- unsupported ellipsis expression
- unsupported varlen array: %w
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/1ce66b58e21a3e96.
Report an issue: GitHub.