vitessio/vitess · error

type %T not supported as bind var: %v

Error message

type %T not supported as bind var: %v

What it means

Returned by bind variable conversion code when a value of an unsupported Go type is passed as a bind variable; only the types known to sqltypes (integers, strings, []byte, bool, float, sqltypes.Value, query.BindVariable, etc.) are accepted.

Source

Thrown at go/sqltypes/bind_variables.go:331

		return bv, nil
	case []Value:
		bv := &querypb.BindVariable{
			Type:   querypb.Type_TUPLE,
			Values: make([]*querypb.Value, len(v)),
		}
		values := make([]querypb.Value, len(v))
		for i, lv := range v {
			lbv, err := BuildBindVariable(lv)
			if err != nil {
				return nil, err
			}
			values[i].Type = lbv.Type
			values[i].Value = lbv.Value
			bv.Values[i] = &values[i]
		}
		return bv, nil
	}
	return nil, fmt.Errorf("type %T not supported as bind var: %v", v, v)
}

// ValidateBindVariables validates a map[string]*querypb.BindVariable.
func ValidateBindVariables(bv map[string]*querypb.BindVariable) error {
	for k, v := range bv {
		if err := ValidateBindVariable(v); err != nil {
			return fmt.Errorf("%s: %v", k, err)
		}
	}
	return nil
}

// ValidateBindVariable returns an error if the bind variable has inconsistent
// fields.
func ValidateBindVariable(bv *querypb.BindVariable) error {
	if bv == nil {
		return errors.New("bind variable is nil")
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Convert the value to a supported type before binding: string, int/uint/float variants, []byte, time.Time, or []T of a supported scalar
  2. For nil, use a typed value such as sqltypes.NULL via an explicit conversion
  3. For lists, build a []string or []int64 etc. of a supported element type
  4. Inspect %T in the message to identify exactly which type leaked in

Example fix

// before
bindVars["filter"] = struct{ A int }{A: 1}
// after
bindVars["filter"] = 1 // or serialize to []byte / JSON string if intended
Defensive patterns

Strategy: type-guard

Validate before calling

if !isBindable(v) { return fmt.Errorf("cannot bind %T", v) }

Type guard

func isBindable(v interface{}) bool {
	switch v.(type) {
	case nil, string, []byte, int, int8, int16, int32, int64,
		uint, uint8, uint16, uint32, uint64, float32, float64,
		time.Time, *querypb.BindVariable:
		return true
	}
	return false
}

Try / catch

bv, err := sqltypes.BuildBindVariable(v)
if err != nil {
	return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "bind var %v: %v", v, err)
}

Prevention

When it happens

Trigger: Passing an unsupported Go type (struct, map, channel, func, nil without a type, nested unsupported slice elements) to BuildBindVariable, directly or via BuildBindVariables.

Common situations: Passing protobuf messages or structs instead of scalars; passing typed-nil pointers; passing slices of unsupported element types; values produced by generic deserialization (JSON/YAML) that need conversion.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/e0c1d9dd0aa0e431. Report an issue: GitHub.