bytebase/bytebase · error
expected []any for row but got %T
Error message
expected []any for row but got %T
What it means
OceanBase advisor getEstimatedRowsFromJSON: an element of the row-data list is not itself a []any row. The JSON explain output was split across elements in an unexpected shape, breaking the concatenation that rebuilds the JSON string.
Source
Thrown at backend/plugin/advisor/oceanbase/common.go:37
if len(res) < 3 {
return 0, errors.Errorf("expected at least 3 elements but got %d", len(res))
}
rowList, ok := res[2].([]any)
if !ok {
return 0, errors.Errorf("expected []any for row data but got %T", res[2])
}
if len(rowList) == 0 {
return 0, errors.Errorf("no data returned from EXPLAIN")
}
// OceanBase might return JSON data split across multiple elements
// We need to concatenate them to form a valid JSON string
var jsonStr string
for _, rowAny := range rowList {
row, ok := rowAny.([]any)
if !ok {
return 0, errors.Errorf("expected []any for row but got %T", rowAny)
}
for _, cellAny := range row {
if cell, ok := cellAny.(string); ok {
jsonStr += cell
}
}
}
if jsonStr == "" {
return 0, errors.Errorf("no JSON data found in EXPLAIN result")
}
var explainData ExplainJSON
if err := json.Unmarshal([]byte(jsonStr), &explainData); err != nil {
return 0, errors.Errorf("failed to parse JSON: %v", err)
}
// Return the estimated rows from the JSON responseView on GitHub (pinned to 1870550677)
Solutions
- Check the %T in the error and fix the driver/serialization layer to emit []any rows.
- Convert other slice types (e.g. []string) to []any in the caller before extraction.
- Use the official OceanBase Go driver or align the wrapper's output.
- Pin a driver version known to produce []any rows for EXPLAIN results.
Example fix
// before
row, ok := rowAny.([]any)
if !ok {
return 0, errors.Errorf("expected []any for row but got %T", rowAny)
}
// after
var row []any
switch r := rowAny.(type) {
case []any:
row = r
case []string:
row = make([]any, len(r))
for i, s := range r {
row[i] = s
}
default:
return 0, errors.Errorf("expected []any for row but got %T", rowAny)
} Defensive patterns
Strategy: type-guard
Validate before calling
func allRowsTyped(rows []any) bool {
for _, r := range rows {
if _, ok := r.([]any); !ok {
return false
}
}
return true
} Type guard
func asRow(v any) ([]any, bool) {
row, ok := v.([]any)
return row, ok
} Prevention
- Convert typed row slices (e.g. []string) to []any at the driver boundary.
- Test the parser with the exact concrete types your driver returns.
- Avoid SDK/proxy wrappers that change row representation.
When it happens
Trigger: A row inside res[2] decoded as []string, map, or nil — typically a custom driver, proxy, or test double that returns rows in a different concrete type than the official OceanBase driver.
Common situations: Third-party drivers decoding rows as typed slices; intermediary API layers reshaping results; mocks returning []string rows.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- expected []any for row data but got %T
- expected at least 3 elements but got %d
- no data returned from EXPLAIN
- no JSON data found in EXPLAIN result
- failed to parse JSON: %v
AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06).
Data as JSON: /api/errors/7ec0c8d186012a34.
Report an issue: GitHub.