{"record":{"id":"fe7fb3d2c8788973","repo":"moeru-ai/airi","slug":"dropped-spark-notify-after-max-attempts","errorCode":null,"errorMessage":"Dropped spark:notify after max attempts:","messagePattern":"Dropped spark:notify after max attempts:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui/src/stores/character/orchestrator/store.ts","lineNumber":238,"sourceCode":"      return\n\n    const [next] = scheduledNotifies.value.splice(nextIndex, 1)\n    removePending(next.event.data.id)\n\n    try {\n      await processSparkNotify(next.event, next.control)\n    }\n    catch (error) {\n      if (next.attempts + 1 < next.maxAttempts) {\n        scheduledNotifies.value = [...scheduledNotifies.value, {\n          ...next,\n          attempts: next.attempts + 1,\n          nextRunAt: computeNextRunAt(next.event, next.attempts + 1),\n        }]\n        pendingNotifies.value = [...pendingNotifies.value, next.event]\n      }\n      else {\n        console.warn('Dropped spark:notify after max attempts:', error)\n      }\n    }\n  }\n\n  function startTicker() {\n    if (tickTimer)\n      return\n\n    tickTimer = setInterval(() => {\n      void tick()\n    }, attentionConfig.value.tickIntervalMs)\n  }\n\n  function stopTicker() {\n    if (!tickTimer)\n      return\n\n    clearInterval(tickTimer)","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui/src/stores/character/orchestrator/store.ts#L220-L256","documentation":"The character orchestrator queues spark:notify events with a retry schedule (attempts + computeNextRunAt backoff). When processSparkNotify throws and the event has already consumed its max attempts, the event is dropped permanently and this warning records the last error. Dropped means the mod's proactive trigger for that tick will never fire — it is data loss for that single notify, bounded by design.","triggerScenarios":"processSparkNotify (which typically invokes mod logic/LLM calls for the notification) keeps failing across all scheduled retries — e.g. the mod throws on the event payload, a downstream provider keeps erroring, or a spark condition references missing state.","commonSituations":"A mod's spark handler has a bug triggered by a specific payload shape; LLM/provider outage lasting longer than the retry window; mod updated to an incompatible event schema; per-event failure that is payload-dependent so every retry fails identically.","solutions":["Read the logged error object — it is the underlying cause from processSparkNotify, not the drop itself.","Fix the failing mod handler (schema mismatch, missing dependency) in the mod source.","If the cause is a transient provider outage, no action: future spark events will process normally.","Increase maxAttempts/backoff only if outages longer than the window are expected and stale notifies are still valuable."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await processSparkNotify(next.event, next.control)\n}\ncatch (error) {\n  if (next.attempts + 1 < next.maxAttempts) {\n    // re-queue with backoff (existing behavior)\n  }\n  else {\n    // log and drop; surface to mod developer tooling if attached\n  }\n}","preventionTips":["Validate spark event payloads before queueing so deterministic failures do not burn retries.","Only enqueue events whose handler failures are plausibly transient (network/provider).","Alert mod authors when their events hit the drop path so bugs get fixed."],"tags":["orchestrator","spark","retry-exhausted","mods"],"backgroundTag":"retry-limit-exceeded","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}