Flow-Launcher/Flow.Launcher · error · SearchException
{e.Message}
Error message
{e.Message} What it means
Thrown as SearchException('Windows Index', e.Message, e) from WindowsIndex.WindowsIndexSearchAsync when the (synchronous) setup of the async enumerable throws InvalidOperationException. Because the body is an iterator, only exceptions raised before the first `yield` are caught here - notably the regex `_reservedPatternMatcher.IsMatch(search)` call. OLE DB failures happen later (inside ExecuteWindowsIndexSearchAsync) and are logged/yield-broken there, not here.
Source
Thrown at Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs:87
// Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
}
internal static IAsyncEnumerable<SearchResult> WindowsIndexSearchAsync(
string connectionString,
string search,
CancellationToken token)
{
try
{
return _reservedPatternMatcher.IsMatch(search)
? AsyncEnumerable.Empty<SearchResult>()
: ExecuteWindowsIndexSearchAsync(search, connectionString, token);
}
catch (InvalidOperationException e)
{
throw new SearchException("Windows Index", e.Message, e);
}
}
internal static bool PathIsIndexed(string path)
{
try
{
var csm = new CSearchManager();
var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager();
return indexManager.IncludedInCrawlScope(path) > 0;
}
catch (COMException)
{
// Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
return false;
}
}
}View on GitHub (pinned to 7fc63b07bb)
Solutions
- Guard the search argument at the top: if (string.IsNullOrEmpty(search)) return AsyncEnumerable.Empty<SearchResult>();
- Move all OLE DB code below the first yield so failures stay inside ExecuteWindowsIndexSearchAsync and are logged, not rethrown as SearchException.
- If SearchException is thrown, inspect InnerException for the real InvalidOperationException stack.
- Add unit tests for the regex against adversarial inputs to make this branch unreachable.
Example fix
// before
internal static IAsyncEnumerable<SearchResult> WindowsIndexSearchAsync(string connectionString, string search, CancellationToken token)
{
try
{
return _reservedPatternMatcher.IsMatch(search)
? AsyncEnumerable.Empty<SearchResult>()
: ExecuteWindowsIndexSearchAsync(search, connectionString, token);
}
catch (InvalidOperationException e)
{
throw new SearchException("Windows Index", e.Message, e);
}
}
// after - guard input and let OLE DB failures stay in the iterator
internal static IAsyncEnumerable<SearchResult> WindowsIndexSearchAsync(string connectionString, string search, CancellationToken token)
{
if (string.IsNullOrEmpty(search) || _reservedPatternMatcher.IsMatch(search))
return AsyncEnumerable.Empty<SearchResult>();
return ExecuteWindowsIndexSearchAsync(search, connectionString, token);
} Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrEmpty(search))
return AsyncEnumerable.Empty<SearchResult>(); Type guard
static bool IsSearchable(string search) => !string.IsNullOrEmpty(search);
Try / catch
try { return WindowsIndex.WindowsIndexSearchAsync(connectionString, search, token); }
catch (SearchException ex) { App.API.LogException(nameof(WindowsIndex), $"{ex.EngineName} query failed", ex.InnerException); return AsyncEnumerable.Empty<SearchResult>(); } Prevention
- Guard against null/empty search at the top of WindowsIndexSearchAsync.
- Keep all OLE DB code below the first yield so failures are logged, not rethrown.
- Inspect SearchException.InnerException for the real InvalidOperationException.
- Unit-test the reserved-pattern regex against adversarial inputs.
When it happens
Trigger: The reserved-pattern regex throws InvalidOperationException - in practice this is rare, but it can occur if the regex engine hits an internal state error or if the search string is null at a callsite that bypassed the empty check. More commonly this catch defends against future changes to the synchronous prologue of the iterator.
Common situations: A caller passes a null `search` (the IsMatch call then throws ArgumentNullException, not InvalidOperationException, so this is mostly defensive); a regex engine regression on a specific Unicode input; refactoring that moves OLE DB connection setup above the first yield would route OleDbException through this catch.
Related errors
- {e.Message}
- The required service for Windows Index Search does not appea
- SHParseDisplayName failed
- SHBindToParent failed
- GetUIObjectOf failed
AI-assisted analysis of Flow-Launcher/Flow.Launcher@7fc63b07bb (2026-08-13).
Data as JSON: /api/errors/53b98372d8ac799e.
Report an issue: GitHub.