vitessio/vitess · error

element does not implement SQLNode

Error message

element does not implement SQLNode

What it means

Error in sqlparser's tracked_buffer: an element of a node list does not implement the SQLNode interface, so it cannot be printed/walked during AST generation. Thrown at go/vt/sqlparser/tracked_buffer.go:282.

Source

Thrown at go/vt/sqlparser/tracked_buffer.go:282

	// SLOW PATH! Add specific cases above to avoid reflection.

	// Check if the input is a slice
	val := reflect.ValueOf(input)
	if val.Kind() != reflect.Slice {
		// Handle the error or return if input is not a slice
		panic("input is not a slice")
	}

	// Iterate over the slice elements
	for i := 0; i < val.Len(); i++ {
		elem := val.Index(i).Interface()

		// Assert each element implements SQLNode
		node, ok := elem.(SQLNode)
		if !ok {
			// Handle the error or skip non-SQLNode elements
			panic("element does not implement SQLNode")
		}

		// Now `node` is of type SQLNode
		// You can call methods or use it as a SQLNode here
		buf.Myprintf("%v", node)
	}
}

func getExpressionForParensEval(checkParens bool, value any) Expr {
	if checkParens {
		expr, isExpr := value.(Expr)
		if isExpr {
			return expr
		}
	}
	return nil
}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Convert elements to their SQLNode wrappers before formatting
  2. Use a string verb (%s) joined with separators for plain strings instead of %n
  3. Ensure the slice type used in Format embeds SQLNode-implementing element types

Example fix

// before
buf.Myprintf("%n", names) // []string
// after
buf.Myprintf("%n", cols) // []SelectExpr (SQLNode)
Defensive patterns

Strategy: type-guard

Validate before calling

for _, e := range elems {
    if _, ok := e.(SQLNode); !ok {
        return fmt.Errorf("%%n slice contains non-SQLNode %T", e)
    }
}

Type guard

func asSQLNodeSlice(v any) ([]SQLNode, bool) {
    rv := reflect.ValueOf(v)
    if rv.Kind() != reflect.Slice {
        return nil, false
    }
    out := make([]SQLNode, 0, rv.Len())
    for i := 0; i < rv.Len(); i++ {
        n, ok := rv.Index(i).Interface().(SQLNode)
        if !ok {
            return nil, false
        }
        out = append(out, n)
    }
    return out, true
}

Prevention

When it happens

Trigger: Passing to %n a slice of non-SQLNode elements, e.g. []string, []Token, or []*topodatapb.X instead of []SQLNode / node slice types.

Common situations: Hand-written Format methods passing auxiliary string slices or internal enum slices with %n.

Related errors


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