bytebase/bytebase · error
expect string, got %T for engine %v
Error message
expect string, got %T for engine %v
What it means
In parseToEngineSQL (backend/store/instance.go), each element of an `engine in [...]` list must be a string literal. This error is thrown when a list element is a non-string Go type (number, bool, etc.), aborting before SQL generation.
Source
Thrown at backend/store/instance.go:1082
if variable != "engine" {
return nil, errors.Errorf(`only "engine" support "engine in [xx]"/"!(engine in [xx])" operator`)
}
if value == nil {
return nil, errors.Errorf(`empty value %v for "engine" operator`, value)
}
list, ok := value.([]any)
if !ok {
return nil, errors.Errorf(`expect list, got %T, hint: filter engine in ["xx"]`, value)
}
if len(list) == 0 {
return nil, errors.Errorf(`empty value %v for "engine" operator`, value)
}
engineList := make([]any, len(list))
for i, raw := range list {
engine, ok := raw.(string)
if !ok {
return nil, errors.Errorf(`expect string, got %T for engine %v`, raw, raw)
}
v1Engine, ok := v1pb.Engine_value[engine]
if !ok {
return nil, errors.Errorf(`invalid engine filter %q`, engine)
}
storeEngine := convertEngine(v1pb.Engine(v1Engine))
engineList[i] = storeEngine
}
return qb.Q().Space("instance.metadata->>'engine' = ANY(?)", engineList), nil
}
getFilter = func(expr celast.Expr) (*qb.Query, error) {
q := qb.Q()
switch expr.Kind() {
case celast.CallKind:
functionName := expr.AsCall().FunctionName()
switch functionName {
case celoperators.LogicalOr:View on GitHub (pinned to 1870550677)
Solutions
- Use the engine name string for each element, e.g. `engine in ["POSTGRES"]`.
- Check v1pb.Engine enum names (Engine_value keys) and use exactly those strings.
- Fix the client filter builder to stringify engine values.
Example fix
// before filter = 'engine in [1, 2]' // after filter = 'engine in ["POSTGRES", "MYSQL"]'
Defensive patterns
Strategy: type-guard
Validate before calling
engineList.forEach(e => { if (typeof e !== 'string') throw new TypeError('engine list items must be strings: ' + e); }); Type guard
const isStringEngineList = (v) => Array.isArray(v) && v.every(x => typeof x === 'string');
Try / catch
try {
return await listInstances({ filter });
} catch (e) {
if (String(e).includes('expect string')) {
filter = buildEngineFilter(engineList.map(String));
return retry(listInstances, { filter });
}
throw e;
} Prevention
- Never pass enum ordinals; always use engine name strings.
- Stringify values when interpolating them into filter templates.
When it happens
Trigger: Filters like `engine in [1, 2]` or `engine in [true]` — numeric or boolean literals inside the engine list.
Common situations: Programmatic filter builders substituting enum ordinal values instead of engine name strings, JSON payloads where engines were serialized as numbers.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- CodeInvalidArgument
- category value must be a string, got %T
- status value must be a string
- query value must be a string
- issue value must be a string
AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06).
Data as JSON: /api/errors/af4d1dafa70a9aed.
Report an issue: GitHub.