{"record":{"id":"bf2c2227f8c1fbaa","repo":"Tencent/WeKnora","slug":"opensearch-cluster-version-unsupported","errorCode":null,"errorMessage":"opensearch: cluster version unsupported","messagePattern":"opensearch: cluster version unsupported","errorType":"error_code","errorClass":"AppError","httpStatus":null,"severity":"error","filePath":"internal/application/repository/retriever/opensearch/errors.go","lineNumber":33,"sourceCode":"\tErrIndexNotFound = errors.New(\"opensearch: index not found\")\n\n\t// ErrDimensionMismatch — embedding dimension violates the per-dim\n\t// invariant (e.g. dim <= 0, dim > 16000, or embeddings within a\n\t// single batch disagree).\n\tErrDimensionMismatch = errors.New(\"opensearch: embedding dimension mismatch\")\n\n\t// ErrAuth — cluster returned 401 / 403. Distinguished from ErrTransport\n\t// so the service layer can map to a clean 4xx instead of 503.\n\tErrAuth = errors.New(\"opensearch: authentication failed\")\n\n\t// ErrTransport — network / 5xx / opaque cluster error. Classified as\n\t// transient: ensureReady does NOT persist this in initErr, so the next\n\t// caller will retry.\n\tErrTransport = errors.New(\"opensearch: transport error\")\n\n\t// ErrVersionUnsupported — cluster is not OpenSearch, is OS 1.x, or is\n\t// OS 2.0~2.3 (pre-Lucene-HNSW-GA). probeVersion enforces.\n\tErrVersionUnsupported = errors.New(\"opensearch: cluster version unsupported\")\n\n\t// ErrConfigInvalid — IndexConfig / storeID / sanitizeIndexName guard\n\t// failed, or the k-NN plugin is missing on one or more cluster nodes.\n\tErrConfigInvalid = errors.New(\"opensearch: invalid index config\")\n\n\t// ErrFeatureNotEnabled — stubs.go returns this from methods whose real\n\t// implementation has not landed yet (CopyIndices / BatchUpdateChunk* /\n\t// swapToVersion, plus the read/write methods that a follow-up commit\n\t// will replace with production code).\n\tErrFeatureNotEnabled = errors.New(\"opensearch: feature not enabled in this build\")\n\n\t// ErrBatchTooLarge — Save / Delete batch exceeded the driver's sync\n\t// cap. Distinct from ErrFeatureNotEnabled so the service layer can\n\t// chunk + retry rather than treat the failure as \"waiting on a future\n\t// implementation.\"\n\tErrBatchTooLarge = errors.New(\"opensearch: batch size exceeds driver cap\")\n\n\t// ErrCircuitBreaker — OpenSearch k-NN circuit breaker returned 429","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/repository/retriever/opensearch/errors.go#L15-L51","documentation":"An AlternativeSubPlan node (planner construct for choosing between IN-list subplans) was found. Like SubPlan, it is an internal representation that never comes from raw user SQL parsing; its presence indicates forged or non-parse-tree input, and the validator blocks it defensively.","triggerScenarios":"Validating a node tree that was produced or mutated after planning, or hand-crafted protobuf ASTs containing Node_AlternativeSubPlan.","commonSituations":"Pipelines that persist/restore planner trees; fuzzing or adversarial input aimed at the validator; mixing plan output into the parse-validate path.","solutions":["Only feed trees obtained from parsing raw SQL text via pg_query.Parse into the validator.","Remove any step that mutates or regenerates the AST between parse and validation.","Validate SQL text at the API boundary and keep parse->validate as a single synchronous step."],"exampleFix":"// before\nnode := loadCachedTree(key) // may be a planner tree\nv.validateNode(node, res)\n\n// after\ntree, _ := pg_query.Parse(rawSQL)\nv.validateNode(tree.Stmts[0].Stmt, res)","handlingStrategy":"type-guard","validationCode":"func validateRawSQL(rawSQL string) error {\n\ttree, err := pg_query.Parse(rawSQL)\n\tif err != nil { return err }\n\treturn validator.ValidateNodeTree(tree) // trees only from fresh Parse\n}","typeGuard":"if _, ok := node.Node.(*pg_query.Node_AlternativeSubPlan); ok {\n\treturn false // planner-only node: input is not a raw parse tree\n}","tryCatchPattern":"if err := validator.ValidateQuery(rawSQL); err != nil {\n\tif strings.Contains(err.Error(), \"AlternativeSubPlan\") {\n\t\treturn fmt.Errorf(\"reject non-parse-tree input: %w\", err)\n\t}\n}","preventionTips":["Reject any API input that is not plain SQL text.","Do not mutate ASTs between parsing and validation.","Monitor occurrences — they indicate forged/adversarial input worth alerting on."],"tags":["sql","security","ast","default-deny"],"backgroundTag":"sql-validation-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}