{"record":{"id":"96c1a42b59511b8d","repo":"Tencent/WeKnora","slug":"opensearch-index-not-found","errorCode":null,"errorMessage":"opensearch: index not found","messagePattern":"opensearch: index not found","errorType":"error_code","errorClass":"AppError","httpStatus":404,"severity":"error","filePath":"internal/application/repository/retriever/opensearch/errors.go","lineNumber":15,"sourceCode":"// Package opensearch implements the RetrieveEngineRepository interface\n// for OpenSearch k-NN native vector search.\npackage opensearch\n\nimport \"errors\"\n\n// Sentinel errors returned by Repository. The service-layer factory wraps\n// these into typed AppError values (2200/2201) — the repository itself\n// never imports internal/errors. The boundary is intentional (directional\n// dependency).\nvar (\n\t// ErrIndexNotFound — alias / underlying index missing. Search and\n\t// delete-by-query operations return this when the per-dim alias has\n\t// not been created yet (no Save has been issued for that dim).\n\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\")","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/repository/retriever/opensearch/errors.go#L1-L33","documentation":"A RangeFunction node was found in the FROM clause — a set-returning function used as a table source, e.g. `FROM generate_series(...)`, `FROM unnest(...)`, or file/network-reading functions. The validator unconditionally blocks these because set-returning functions can invoke arbitrary server-side code (file reads, command execution via extensions) regardless of configuration.","triggerScenarios":"Validating `SELECT * FROM generate_series(1,10)`, `SELECT * FROM unnest(ARRAY[1,2])`, `SELECT * FROM read_text('/etc/passwd')`, or a hidden RangeFunction inside an otherwise-allowed FROM subquery.","commonSituations":"Analytics queries that naturally use generate_series/unnest to expand rows; exploit attempts smuggling functions in FROM; SQL generation code that emits table-valued functions instead of joining real tables.","solutions":["Replace the function source with a real table: materialize the series/rows into a temp or permanent table outside the validated query and select from it.","For generate_series-style row expansion, do the expansion in application code and pass values as parameters (e.g. `WHERE id = ANY($1)`).","For unnest, pass the array as a parameter and expand client-side, since `SELECT unnest($1::int[])` in the target list is validated by function rules, whereas FROM-range functions are always denied."],"exampleFix":"// before\nSELECT * FROM generate_series(1, 10) AS n;\n\n// after\nSELECT id FROM my_numbers WHERE id BETWEEN 1 AND 10;","handlingStrategy":"validation","validationCode":"var fromFunc = regexp.MustCompile(`(?i)\\bfrom\\s+[a-z_][a-z0-9_]*\\s*\\(`)\nif fromFunc.MatchString(sql) {\n\t// reject or rewrite: set-returning functions cannot be a FROM source\n}","typeGuard":null,"tryCatchPattern":"if err := validator.ValidateQuery(sql); err != nil {\n\tif strings.Contains(err.Error(), \"functions in FROM clause\") {\n\t\treturn fmt.Errorf(\"materialize function output into a table first: %w\", err)\n\t}\n}","preventionTips":["Materialize generate_series/unnest results into temp tables before querying.","Do row expansion in application code and pass arrays/ids as parameters.","Treat FROM-clause functions in user input as an attack signal and alert rather than rewrite blindly."],"tags":["sql","security","function-call","validation"],"backgroundTag":"function-not-allowed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}