{"record":{"id":"965ebfc1aac1e61c","repo":"moeru-ai/airi","slug":"beat-sync-is-not-available-in-stage-pocket","errorCode":null,"errorMessage":"Beat Sync is not available in Stage Pocket","messagePattern":"Beat Sync is not available in Stage Pocket","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/stage-shared/src/beat-sync/detector.ts","lineNumber":256,"sourceCode":"}\n\nlet detector: BeatSyncDetector | undefined\nfunction getDetector() {\n  if (!isStageWeb())\n    throw new Error('getDetector() is only available in Stage Web environment')\n\n  if (!detector)\n    detector = createBeatSyncDetector({ env: StageEnvironment.Web })\n\n  return detector\n}\n\nlet context: ReturnType<typeof createContext> | undefined\n\nfunction installCapacitorHandlers(context: ReturnType<typeof createContext>) {\n  defineInvokeHandler(context, beatSyncToggleInvokeEventa, async (enabled) => {\n    if (enabled)\n      throw new Error('Beat Sync is not available in Stage Pocket')\n  })\n  defineInvokeHandler(context, beatSyncGetStateInvokeEventa, async () => ({ isActive: false }))\n  defineInvokeHandler(context, beatSyncUpdateParametersInvokeEventa, async () => {})\n  defineInvokeHandler(context, beatSyncGetInputByteFrequencyDataInvokeEventa, async () => {\n    return new Uint8Array(inputAnalyserFFTSize / 2)\n  })\n}\n\nfunction getContext() {\n  if (!context) {\n    context = createContext()\n\n    // Capacitor cannot capture system audio. Register every request handler so\n    // callers receive deterministic inactive results instead of pending forever.\n    if (isStageCapacitor())\n      installCapacitorHandlers(context)\n  }\n","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-shared/src/beat-sync/detector.ts#L238-L274","documentation":"Thrown by the Capacitor (Stage Pocket) install handler for the beat-sync toggle invoke event whenever a caller attempts to enable beat sync. Beat Sync relies on desktop screen/audio capture APIs that are not available on mobile, so the Pocket handler intentionally rejects any enable request while still answering state/parameter handlers as no-ops. It is a feature-availability guard, not a transient failure.","triggerScenarios":"On the Stage Pocket (Capacitor mobile) build, any UI or IPC path that invokes `beatSyncToggleInvokeEventa` with `enabled = true`. The handler throws synchronously inside the invoke callback, so the IPC call rejects on the caller side.","commonSituations":"Sharing UI code between desktop and mobile stages where the Beat Sync toggle is still exposed; invoking the mobile handler from a settings page or quick-action without gating it on platform capability; automated tests running against the Pocket handler with enable=true.","solutions":["Gate the Beat Sync toggle UI on platform capability so it is hidden/disabled on Stage Pocket rather than invoked.","If the invoke may still arrive, catch it on the caller side and show a 'not available on mobile' notice instead of surfacing the raw error.","Do not attempt feature-detection workarounds — mobile platforms lack the required capture APIs by design.","Confirm the build target: this only fires on the Pocket (Capacitor) handler, not on Web or Tamagotchi."],"exampleFix":"// before\ninvokeBeatSyncToggle(true)\n\n// after\nif (isStagePocket) {\n  showUser('Beat Sync is not available on Stage Pocket.')\n} else {\n  invokeBeatSyncToggle(true)\n}","handlingStrategy":"validation","validationCode":"const isStagePocket = Capacitor.getPlatform() !== 'web' && isMobileBuild\nif (isStagePocket) {\n  showUser('Beat Sync is not available on Stage Pocket.')\n  return\n}\ninvokeBeatSyncToggle(true)","typeGuard":"function isBeatSyncSupported(platform: string): boolean {\n  return platform === 'web' || platform === 'electron'\n}","tryCatchPattern":"try {\n  await invokeBeatSyncToggle(true)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Beat Sync is not available in Stage Pocket') {\n    showUser('Beat Sync is not available on Stage Pocket.')\n    return\n  }\n  throw e\n}","preventionTips":["Gate the Beat Sync toggle UI on platform capability; hide it on Stage Pocket.","Do not invoke the Pocket beat-sync enable handler even if the UI is reachable.","Catch the error on the caller side and show a friendly notice instead of surfacing the raw message.","Remember beat sync depends on desktop capture APIs absent on mobile by design."],"tags":["beat-sync","stage-pocket","capacitor","platform-support","feature-unavailable"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}