Tencent/WeKnora · error · AppError

opensearch: transport error

Error message

opensearch: transport error

What it means

A SubPlan node was found during AST validation. SubPlan is an internal planner representation that never appears in raw parsed user SQL; encountering one means the input is not a plain parse tree (pre-planned or forged input), so the validator rejects it defensively as part of its default-deny posture.

Source

Thrown at internal/application/repository/retriever/opensearch/errors.go:29

var (
	// ErrIndexNotFound — alias / underlying index missing. Search and
	// delete-by-query operations return this when the per-dim alias has
	// not been created yet (no Save has been issued for that dim).
	ErrIndexNotFound = errors.New("opensearch: index not found")

	// ErrDimensionMismatch — embedding dimension violates the per-dim
	// invariant (e.g. dim <= 0, dim > 16000, or embeddings within a
	// single batch disagree).
	ErrDimensionMismatch = errors.New("opensearch: embedding dimension mismatch")

	// ErrAuth — cluster returned 401 / 403. Distinguished from ErrTransport
	// so the service layer can map to a clean 4xx instead of 503.
	ErrAuth = errors.New("opensearch: authentication failed")

	// ErrTransport — network / 5xx / opaque cluster error. Classified as
	// transient: ensureReady does NOT persist this in initErr, so the next
	// caller will retry.
	ErrTransport = errors.New("opensearch: transport error")

	// ErrVersionUnsupported — cluster is not OpenSearch, is OS 1.x, or is
	// OS 2.0~2.3 (pre-Lucene-HNSW-GA). probeVersion enforces.
	ErrVersionUnsupported = errors.New("opensearch: cluster version unsupported")

	// ErrConfigInvalid — IndexConfig / storeID / sanitizeIndexName guard
	// failed, or the k-NN plugin is missing on one or more cluster nodes.
	ErrConfigInvalid = errors.New("opensearch: invalid index config")

	// ErrFeatureNotEnabled — stubs.go returns this from methods whose real
	// implementation has not landed yet (CopyIndices / BatchUpdateChunk* /
	// swapToVersion, plus the read/write methods that a follow-up commit
	// will replace with production code).
	ErrFeatureNotEnabled = errors.New("opensearch: feature not enabled in this build")

	// ErrBatchTooLarge — Save / Delete batch exceeded the driver's sync
	// cap. Distinct from ErrFeatureNotEnabled so the service layer can
	// chunk + retry rather than treat the failure as "waiting on a future

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Ensure the validated input comes directly from pg_query.Parse of raw SQL, never from planner output or a persisted plan tree.
  2. Drop any cache layer that stores post-parse/planner node trees and re-parse the raw SQL instead.
  3. Reject at the input boundary: validate that submitted SQL is plain text before parsing.

Example fix

// before
plan := planner.Plan(sql)
err := validator.ValidateNodeTree(plan)

// after
tree, _ := pg_query.Parse(sql)
err := validator.ValidateNodeTree(tree)
Defensive patterns

Strategy: type-guard

Validate before calling

func isFreshParseTree(tree *pg_query.ParseResult, rawSQL string) bool {
	// only validate trees produced directly from parsing rawSQL in this request
	return tree != nil && parseCacheOrigin[tree] == rawSQL
}

Type guard

if _, ok := node.Node.(*pg_query.Node_SubPlan); ok {
	return false // not a raw parse-tree node; reject input source
}

Try / catch

if err := validator.ValidateQuery(rawSQL); err != nil {
	if strings.Contains(err.Error(), "SubPlan") {
		return fmt.Errorf("input must be raw SQL text, not a plan tree: %w", err)
	}
}

Prevention

When it happens

Trigger: Passing a parsed/planner-processed query tree (not a freshly pg_query-parsed statement) into validateNode, or crafted protobuf input containing a SubPlan node.

Common situations: Caching parse trees across planner stages; feeding plans (EXPLAIN output trees) rather than parse trees into the validator; security research probing the validator with hand-built nodes.

Related errors


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