{"record":{"id":"6699c379ca7eb613","repo":"sinelaw/fresh","slug":"producererror","errorCode":null,"errorMessage":"producerError","messagePattern":"producerError","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/plugins/search_replace.ts","lineNumber":1533,"sourceCode":"\n      // Yield to the JS event loop between chunks. `delay(0)` is\n      // enough — it lets queued plugin handlers (Tab, typed input,\n      // Esc) run between our streaming work. When there's no\n      // carryover, wait the usual pump interval so we don't hot-loop\n      // on `handle.take()`.\n      const yieldMs = moreInQueue ? 0 : SEARCH_PUMP_INTERVAL_MS;\n      await editor.delay(yieldMs);\n    }\n\n    if (activeSearchHandle === handle) {\n      activeSearchHandle = null;\n    }\n\n    // Final state\n    if (generation !== currentSearchGeneration || !panel) return allResults;\n\n    if (producerError) {\n      throw new Error(producerError);\n    }\n\n    panel.truncated = truncated;\n\n    if (!silent) {\n      if (allResults.length === 0) {\n        editor.setStatus(editor.t(\"status.no_matches\", { pattern }));\n      } else if (panel.truncated) {\n        editor.setStatus(editor.t(\"status.found_matches\", { count: String(allResults.length) }) + \" \" + editor.t(\"panel.limited\"));\n      } else {\n        editor.setStatus(editor.t(\"status.found_matches\", { count: String(allResults.length) }));\n      }\n    }\n    return allResults;\n  } catch (e) {\n    if (!silent) {\n      editor.setStatus(editor.t(\"status.search_error\", { error: String(e) }));\n    }","sourceCodeStart":1515,"sourceCodeEnd":1551,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/plugins/search_replace.ts#L1515-L1551","documentation":"During a search-and-replace scan, errors that occur on the producer side (the async search loop) are stored in a producerError string instead of thrown immediately, so the function can finish its bookkeeping. Once the run completes, if producerError was captured, it is rethrown here verbatim. The message is opaque ('producerError' is the template's variable) but the underlying cause is whatever the producer recorded — e.g. a search worker failure or panel/generation inconsistency.","triggerScenarios":"A search generation's producer loop encounters an error (worker exception, callback failure) and stores it in producerError; when searchReplace finishes and generation still matches currentSearchGeneration with a live panel, line 1533 rethrows it. Also triggered whenever a prior search step set producerError before final state was reached.","commonSituations":"Regex compilation failures in the search producer, worker/thread crashes during large-corpus scans, plugin API errors surfaced inside the search callback, stale-generation races where an error was recorded mid-scan.","solutions":["Look at the full caught error/log output around the search run — this throw rethrows the original producer message, so fix the underlying producer failure.","Verify the search pattern (regex validity, encoding) passed to search_replace.","Retry the operation; transient producer failures (e.g. during concurrent panel updates) often resolve on a fresh generation.","If it persists, check that the search panel is open and the generation state is not being reset concurrently by other plugin calls."],"exampleFix":"// before\nawait searchReplace({ pattern: userPattern, replace: repl });\n\n// after\ntry {\n  await searchReplace({ pattern: userPattern, replace: repl });\n} catch (e) {\n  console.error(\"search failed:\", e.message);\n  new RegExp(userPattern); // validate regex before retry\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const results = await searchReplace(opts);\n} catch (e) {\n  // producerError is a rethrow of the original producer failure\n  log.error(\"search_replace failed:\", e.message);\n  // inspect pattern/panel state, then retry once with a fresh call\n}","preventionTips":["Validate search patterns (especially regexes) before running search_replace.","Keep the search panel open and avoid concurrent search calls that bump the generation counter.","Log the full error — the thrown message is the original producer failure, not a new one.","Retry transient failures once with a fresh searchReplace call."],"tags":["async","error-propagation","search"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}