Tencent/WeKnora · error

WITH clause (CTEs) is not allowed

Error message

WITH clause (CTEs) is not allowed

What it means

When the validator is configured with checkCTEs enabled, validateSelectStmt rejects any SELECT carrying a WITH clause (stmt.WithClause != nil). Common Table Expressions are disallowed because they can obscure which tables are actually referenced, defeating the validator's table allowlisting. The query is rejected before the FROM clause is inspected.

Source

Thrown at internal/utils/inject.go:1353

	if len(sql) > v.maxLength {
		return fmt.Errorf("SQL query too long (max %d characters)", v.maxLength)
	}

	return nil
}

// validateSelectStmt validates a SELECT statement with configured options
func (v *sqlValidator) validateSelectStmt(stmt *pg_query.SelectStmt, result *SQLValidationResult) error {
	tablesInQuery := make(map[string]string) // table name -> alias

	// Check for UNION/INTERSECT/EXCEPT (compound queries)
	if stmt.Op != pg_query.SetOperation_SETOP_NONE {
		return fmt.Errorf("compound queries (UNION/INTERSECT/EXCEPT) are not allowed")
	}

	// Check for WITH clause (CTEs)
	if v.checkCTEs && stmt.WithClause != nil {
		return fmt.Errorf("WITH clause (CTEs) is not allowed")
	}

	// Check for INTO clause (SELECT INTO)
	if stmt.IntoClause != nil {
		return fmt.Errorf("SELECT INTO is not allowed")
	}

	// Check for LOCKING clause (FOR UPDATE, etc.)
	if len(stmt.LockingClause) > 0 {
		return fmt.Errorf("locking clauses (FOR UPDATE, etc.) are not allowed")
	}

	// Validate FROM clause
	for _, fromItem := range stmt.FromClause {
		if err := v.validateFromItem(fromItem, tablesInQuery, result); err != nil {
			return err
		}
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inline the CTE as a subquery in FROM: SELECT * FROM (SELECT ...) AS t.
  2. Duplicate the underlying query logic without WITH.
  3. Disable the checkCTEs option in the validator if CTEs are safe in your context.

Example fix

// before (rejected when checkCTEs=true)
q := "WITH active AS (SELECT id FROM users WHERE active) SELECT * FROM active"

// after
q := "SELECT * FROM (SELECT id FROM users WHERE active) AS active"
Defensive patterns

Strategy: validation

Validate before calling

re := regexp.MustCompile(`(?i)^\s*WITH[\s(]`)
if re.MatchString(sql) {
    return fmt.Errorf("CTE (WITH clause) rejected; inline it as a subquery or disable checkCTEs")
}

Prevention

When it happens

Trigger: Calling the validation API with a query like "WITH t AS (SELECT ...) SELECT * FROM t" while the validator has checkCTEs = true (whether by explicit option or default).

Common situations: Developers refactor long queries into CTEs for readability and suddenly fail validation; query builders that emit WITH for recursive or reusable subqueries; teams upgrading the library where checkCTEs defaults changed to true.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/d218476276a827c3. Report an issue: GitHub.