{"record":{"id":"54cac57d08734eea","repo":"languagetool-org/languagetool","slug":"exception-during-search-for-query-query-on-rul","errorCode":null,"errorMessage":"Exception during search for query + query + on rule + rule.getId()","messagePattern":"Exception during search for query \\+ query \\+ on rule \\+ rule\\.getId\\(\\)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-wikipedia/src/main/java/org/languagetool/dev/index/Searcher.java","lineNumber":190,"sourceCode":"          searchThread.join(maxSearchTimeMillis);\n        } else {\n          searchThread.join(Integer.MAX_VALUE);\n        }\n      } catch (InterruptedException e) {\n        throw new RuntimeException(\"Search thread got interrupted for query \" + query, e);\n      }\n      if (searchThread.isAlive()) {\n        // join() timed out and the thread is still running, so its result isn't ready yet -\n        // interrupt it and bail out instead of falling through with a null result\n        searchThread.interrupt();\n        throw new SearchTimeoutException(\"Search timeout of \" + maxSearchTimeMillis + \"ms reached for query \" + query);\n      }\n      Exception exception = runnable.getException();\n      if (exception != null) {\n        if (exception instanceof SearchTimeoutException) {\n          throw (SearchTimeoutException)exception;\n        }\n        throw new RuntimeException(\"Exception during search for query \" + query + \" on rule \" + rule.getId(), exception);\n      }\n\n      List<MatchingSentence> matchingSentences = runnable.getMatchingSentences();\n      SearcherResult searcherResult = new SearcherResult(matchingSentences, runnable.docsChecked, query);\n      searcherResult.setMaxDocChecked(runnable.getMaxDocChecked());\n      searcherResult.setHasTooManyLuceneMatches(runnable.hasTooManyLuceneMatches());\n      searcherResult.setLuceneMatchCount(runnable.getLuceneMatchCount());\n      searcherResult.setSkipHits(skipHits);\n      searcherResult.setNumDocs(runnable.numDocs);\n      if (runnable.hasTooManyLuceneMatches()) {\n        // more potential matches than we can check in an acceptable time :-(\n        searcherResult.setDocCount(maxHits);\n      } else {\n        searcherResult.setDocCount(getDocCount(indexSearcher));\n      }\n      //TODO: the search itself could also timeout, don't just ignore that:\n      //searcherResult.setResultIsTimeLimited(limitedTopDocs.resultIsTimeLimited);\n      return searcherResult;","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-wikipedia/src/main/java/org/languagetool/dev/index/Searcher.java#L172-L208","documentation":"findRuleMatchesOnIndex collects any Exception thrown by the worker search thread and rethrows it as a RuntimeException wrapping the original, annotated with the query and rule ID. It signals the search thread itself failed with an unexpected exception (anything other than SearchTimeoutException).","triggerScenarios":"The worker search thread (runnable) threw a non-timeout Exception during query execution for the given rule; the wrapper rethrows it here.","commonSituations":"Lucene parse errors from a malformed query, IO errors reading the index, bugs in rule handling inside the search thread; the original stack trace is the cause of this RuntimeException.","solutions":["Inspect the cause exception printed in the stack trace to find the real failure","Fix the malformed query or rule that caused the underlying exception","Verify the Lucene index is not corrupted (rebuild it if IO errors persist)","If intended, catch RuntimeException and check the cause for SearchTimeoutException handling"],"exampleFix":"// before\nthrow new RuntimeException(\"Exception during search for query \" + query + \" on rule \" + rule.getId(), exception);\n// after (caller-side handling)\ntry {\n  result = searcher.findRuleMatchesOnIndex(query, rule, timeout);\n} catch (RuntimeException e) {\n  LOG.error(\"search failed for rule \" + rule.getId(), e.getCause());\n}","handlingStrategy":"try-catch","validationCode":"// validate query syntax before submitting\nQuery q = parser.parse(queryString); // throws ParseException early","typeGuard":null,"tryCatchPattern":"try {\n  result = searcher.findRuleMatchesOnIndex(query, rule, timeout);\n} catch (RuntimeException e) {\n  Throwable cause = e.getCause();\n  LOG.error(\"search failed on rule \" + rule.getId() + \": \" + cause, cause);\n}","preventionTips":["Always inspect the cause chain of wrapped RuntimeExceptions","Validate Lucene query syntax before running","Monitor index integrity"],"tags":["lucene","search","wrapped-exception"],"backgroundTag":"api-request-failed","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}