sinelaw/fresh · error
${provider.name}: ${e instanceof Error ? e.message …
Error message
${provider.name}: ${e instanceof Error ? e.message : String(e)} What it means
In live_grep's searchFiles wrapper, when an individual provider (rg, ag, git grep, ack, grep, or a user-registered one) throws, the error is logged via editor.error and re-thrown wrapped as "<providerName>: <original message>". This preserves which backend failed while propagating the underlying cause (typically one of the 'X exited with code N' errors or a spawn failure like 'binary not found').
Solutions
- Read the wrapped provider name to identify which backend failed, then apply that backend's specific fix (see the per-provider 'exited with code' errors).
- Catch this error at the call site and fall back to the buffers/diagnostics scopes when file search is unavailable.
- Install ripgrep so the primary provider succeeds.
- If a custom provider is at fault, fix or remove its registration from init.ts.
Example fix
// before
const results = await searchFiles(query);
// after
let results;
try {
results = await searchFiles(query);
} catch (e) {
editor.error(`file search unavailable: ${e}`);
results = null; // continue with buffers/diagnostics scopes
} Defensive patterns
Strategy: try-catch
Validate before calling
// check at least one backend exists before searching
const backends = ["rg", "ag", "git", "ack", "grep"];
for (const b of backends) { try { await editor.spawnProcess(b, ["--version"], cwd); break; } catch {} } Type guard
function isProviderError(e: unknown): e is Error { return e instanceof Error && /^\w+: /.test(e.message); } // 'providerName: cause' shape Try / catch
try {
const files = await searchFiles(query);
} catch (e) {
const provider = String(e).split(":")[0];
editor.error(`backend ${provider} failed — degrading to buffers/diagnostics scopes`);
files = null;
} Prevention
- Parse the '<provider>: <cause>' prefix to know which backend failed.
- Always install ripgrep as the primary backend.
- Keep buffers/diagnostics scopes enabled so a file-backend failure is not fatal.
- Test custom providers registered via the plugin API in isolation.
When it happens
Trigger: Any live-grep file-scope search in which the selected/first available provider throws — e.g. rg exiting non-zero, a missing backend binary, or a registered provider raising its own error during the search call.
Common situations: Debugging why live-grep shows no results: the wrapped message names the failing backend; users on machines without ripgrep hitting a spawn failure; user-registered custom providers (via the plugin API) throwing their own errors.
Related errors
- rg exited with code
- ag exited with code
- git grep exited with code
- ack exited with code
- grep exited with code
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/016c2941e9a49d19.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/plugins/live_grep.ts:973
// Run the project-file grep for the enabled file-backed scopes
// (`files` / `ignored`). Returns null when no provider is available so
// the caller can decide whether that's fatal (no other scope on) or
// merely a skipped source.
async function searchFiles(query: string): Promise<GrepMatch[] | null> {
const provider = await selectProvider();
if (!provider) return null;
try {
const results = await provider.search(query, {
cwd: editor.getCwd(),
maxResults: MAX_RESULTS,
includeIgnored: scopeEnabled.ignored,
wholeWord: searchModes.word,
regex: searchModes.regex,
});
return results.map((m) => ({ ...m, source: "files" as const }));
} catch (e) {
editor.error(`[live_grep:${provider.name}] ${e}`);
throw new Error(`${provider.name}: ${e instanceof Error ? e.message : String(e)}`);
}
}
// Fan the query out across every enabled scope and merge into one
// capped, tagged result list. Order is files → buffers → diagnostics
// so the most common hits lead.
async function search(query: string): Promise<GrepMatch[]> {
lastQuery = query;
const wasTruncated = lastSearchTruncated;
const results: GrepMatch[] = [];
const remaining = () => MAX_RESULTS - results.length;
if (scopeEnabled.files || scopeEnabled.ignored) {
const fileMatches = await searchFiles(query);
if (fileMatches === null) {
// No grep backend. Only fatal if there's nothing else to search.
if (!scopeEnabled.buffers && !scopeEnabled.diagnostics) {
throw new Error(View on GitHub (pinned to 67894ca546)