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

  1. Use the engine name string for each element, e.g. `engine in ["POSTGRES"]`.
  2. Check v1pb.Engine enum names (Engine_value keys) and use exactly those strings.
  3. 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

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


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/af4d1dafa70a9aed. Report an issue: GitHub.