moeru-ai/airi · error · Error
Beat Sync is not available in Stage Pocket
Error message
Beat Sync is not available in Stage Pocket
What it means
On Stage Pocket (the Capacitor mobile build), beat-sync has no implementation, so the Eventa invoke handler for beatSyncToggleInvokeEventa is registered to throw this error whenever it is invoked with enabled=true (packages/stage-shared/src/beat-sync/detector.ts:256). It is a deliberate capability guard, not a bug: desktop capture analysis cannot run on the mobile platform.
Solutions
- Gate the toggle UI on platform (hide it on Stage Pocket) so the invoke never fires
- Catch this error where toggle is invoked and show an 'unsupported on this device' notice
- Use the state getters (beatSyncGetStateInvokeEventa returns isActive:false) to render the off state instead of toggling
Example fix
// before
await invoke(beatSyncToggleInvokeEventa, true) // throws on Pocket
// after
import { isCapacitorNative } from '../utils/platform'
if (!isCapacitorNative())
await invoke(beatSyncToggleInvokeEventa, true) Defensive patterns
Strategy: validation
Validate before calling
import { Capacitor } from '@capacitor/core'
const beatSyncSupported = !Capacitor.isNativePlatform() // Pocket = native Capacitor build
if (beatSyncSupported)
await invoke(beatSyncToggleInvokeEventa, enabled) Type guard
const isStagePocket = (): boolean => Capacitor.isNativePlatform()
function supportsBeatSync(env: 'web' | 'tamagotchi' | 'pocket'): boolean {
return env !== 'pocket'
} Try / catch
try {
await invoke(beatSyncToggleInvokeEventa, true)
}
catch (error) {
if (error instanceof Error && error.message === 'Beat Sync is not available in Stage Pocket') {
toast('Beat Sync is not supported on this device')
return
}
throw error
} Prevention
- Gate the beat-sync toggle UI by platform before it can be enabled
- Read state via beatSyncGetStateInvokeEventa instead of toggling on unsupported platforms
- Add a feature matrix check when sharing settings pages across stages
When it happens
Trigger: UI code shared across platforms calling the beat-sync toggle with enabled=true inside the Pocket build, or a settings page that was not platform-gated and lets the user flip the toggle on mobile.
Common situations: Reusing the desktop settings UI on mobile, feature flags that forget to exclude pocket, or code paths migrated without a platform check.
Related errors
- CAP_VITE_CAP_ARGS_JSON must be a JSON string array.
- cap-vite [vite args...] -- <ios|android> [cap run args...]
- Expected `cap run --list --json` to return a JSON array.
- No audio track available in the stream
- No devices or simulators found. Connect a device, start a…
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/965ebfc1aac1e61c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/stage-shared/src/beat-sync/detector.ts:256
}
let detector: BeatSyncDetector | undefined
function getDetector() {
if (!isStageWeb())
throw new Error('getDetector() is only available in Stage Web environment')
if (!detector)
detector = createBeatSyncDetector({ env: StageEnvironment.Web })
return detector
}
let context: ReturnType<typeof createContext> | undefined
function installCapacitorHandlers(context: ReturnType<typeof createContext>) {
defineInvokeHandler(context, beatSyncToggleInvokeEventa, async (enabled) => {
if (enabled)
throw new Error('Beat Sync is not available in Stage Pocket')
})
defineInvokeHandler(context, beatSyncGetStateInvokeEventa, async () => ({ isActive: false }))
defineInvokeHandler(context, beatSyncUpdateParametersInvokeEventa, async () => {})
defineInvokeHandler(context, beatSyncGetInputByteFrequencyDataInvokeEventa, async () => {
return new Uint8Array(inputAnalyserFFTSize / 2)
})
}
function getContext() {
if (!context) {
context = createContext()
// Capacitor cannot capture system audio. Register every request handler so
// callers receive deterministic inactive results instead of pending forever.
if (isStageCapacitor())
installCapacitorHandlers(context)
}
View on GitHub (pinned to 677329427f)