bytebase/bytebase · error

unsupported query node type %T

Error message

unsupported query node type %T

What it means

extractPseudoTableFromQueryNode handles only SELECT, set operations, ResultScanStmt, and ShowStmt nodes; any other AST node reaching it is rejected with errors.Errorf("unsupported query node type %T"). It is a fail-closed guard in the Snowflake query span extractor: the node got classified as base.Select (so it wasn't short-circuited earlier) but the extractor cannot compute result columns for that statement shape. The ShowStmt/ResultScanStmt branches exist specifically for SHOW ... ->> query and related result-pipe statements whose $1 input schema cannot be resolved.

Source

Thrown at backend/plugin/parser/snowflake/query_span_extractor.go:193

				return nil, err
			}
			defer func() {
				q.ctes = q.ctes[:originalCTECount]
			}()
		}
		return q.extractPseudoTableFromSetOperation(n)
	case *ast.ResultScanStmt:
		// FAIL CLOSED: a result-pipe (->>) query reads the previous statement's
		// result set, which has no resolvable schema here; resolving the trailing
		// SELECT against $1 would produce wrong lineage. Same posture as PIVOT.
		return nil, errors.New("result-pipe (->>) statements are not supported for query span extraction yet")
	case *ast.ShowStmt:
		// Only reachable for SHOW ... ->> <query> (a plain SHOW classifies
		// SelectInfoSchema and returns before extraction). Same fail-closed
		// posture as ResultScanStmt: $1's schema is not resolvable.
		return nil, errors.New("result-pipe (->>) statements are not supported for query span extraction yet")
	default:
		return nil, errors.Errorf("unsupported query node type %T", node)
	}
}

// leftmostSelect descends a set-operation chain's left spine to the SelectStmt
// that textually leads the statement (where omni attaches a leading WITH).
func leftmostSelect(node ast.Node) *ast.SelectStmt {
	switch n := node.(type) {
	case *ast.SelectStmt:
		return n
	case *ast.SetOperationStmt:
		return leftmostSelect(n.Left)
	default:
		return nil
	}
}

// isRecursiveWith reports whether any CTE in the WITH list carries the RECURSIVE
// flag. Snowflake applies RECURSIVE to the whole WITH list, so a single

View on GitHub (pinned to 1870550677)

Solutions

  1. Restrict GetQuerySpan input to plain SELECT statements or set operations (UNION/INTERSECT/EXCEPT) — the only fully supported shapes.
  2. Identify the concrete node type from the %T value in the message and check whether that construct is intentionally unsupported (e.g. result-pipe ->>); rewrite the query without it.
  3. Handle USE/SET and non-SELECT statements before calling the extractor; non-Select query types already return early and should not reach extraction.
  4. If the node type is a legitimate SELECT-like statement, file/patch the extractor to add a case for it in extractPseudoTableFromQueryNode.
  5. Pin the parser/omni version consistently with the extractor version to avoid new unhandled AST node types.

Example fix

// before
span, err := extractor.GetQuerySpan(ctx, "SHOW TABLES IN SCHEMA s ->> $1")
// after: run the result-pipe query outside lineage, extract span for the plain SELECT
span, err := extractor.GetQuerySpan(ctx, "SELECT id, name FROM s.tbl")
Defensive patterns

Strategy: validation

Validate before calling

// Go: pre-screen statements the extractor cannot model
func supportedForSpan(stmt string) bool {
	s := strings.ToUpper(strings.TrimSpace(stmt))
	return strings.HasPrefix(s, "SELECT") || strings.HasPrefix(s, "WITH") ||
		strings.Contains(s, "UNION") || strings.Contains(s, "INTERSECT") || strings.Contains(s, "EXCEPT")
}

Try / catch

span, err := extractor.GetQuerySpan(ctx, stmt)
if err != nil {
	if strings.HasPrefix(err.Error(), "unsupported query node type") ||
		strings.Contains(err.Error(), "result-pipe (->>) statements are not supported") {
		log.Printf("statement shape unsupported for lineage: %v", err)
		return nil // skip lineage for this statement
	}
	return err
}

Prevention

When it happens

Trigger: Calling GetQuerySpan with a Snowflake statement that the classifier marks as a query but extractPseudoTableFromQueryNode has no case for — i.e. any node type other than *ast.SelectStmt, *ast.SetOperationStmt, *ast.ResultScanStmt, or *ast.ShowStmt (e.g. unusual command forms, PIVOT/other constructs depending on parser version, or a node type newly emitted by a parser upgrade).

Common situations: Feeding non-SELECT commands (CALL, INSERT ... SELECT edge shapes, EXPLAIN variants) that the type classifier still labels Select; parser version drift after an upgrade introduces a new statement type not yet handled; BUG-containing queries mixing constructs the extractor doesn't model; SHOW ... ->> (...) result-pipe queries hitting the fail-closed branch.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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