different-ai/openwork · error
Microphone capture is unavailable in this runtime.
Error message
Microphone capture is unavailable in this runtime.
What it means
Before connecting the realtime session the panel checks that the runtime supports microphone capture via navigator.mediaDevices?.getUserMedia. In environments where the Media Devices API is unavailable (non-secure contexts, runtimes without media permissions), enabling audio input cannot work, so it throws.
Source
Thrown at apps/app/src/react-app/domains/session/voice/voice-panel.tsx:484
requestRealtimeResponse(channel, false);
} else {
setRuntimeStatus(voiceRealtime.micMuted ? "muted" : "listening");
}
return;
}
if (type === "error") {
voiceRealtime.responseInProgress = false;
const error = readRecord(event, "error");
const message = typeof error.message === "string" ? error.message : "Realtime returned an error.";
addEntry("system", message, { error: true });
setRuntimeStatus("error", message);
}
}, [addEntry, props.sessionId, requestRealtimeResponse, setRuntimeStatus]);
const connectRealtime = useCallback(async (audioInput = true) => {
const client = props.client;
if (!client) throw new Error("OpenWork host connection is not ready.");
if (audioInput && !navigator.mediaDevices?.getUserMedia) throw new Error("Microphone capture is unavailable in this runtime.");
disconnectRealtime(true);
setRuntimeStatus("connecting", "Minting Realtime session...");
const sessionContext = await loadVoiceSessionContext(props.opencodeBaseUrl, props.openworkToken, props.sessionId);
const realtimeSession = await client.createVoiceRealtimeSession({ sessionContext });
const peer = new RTCPeerConnection();
voiceRealtime.peer = peer;
if (audioInput) {
setRuntimeStatus("connecting", "Requesting microphone...");
const macPermissionGranted = await requestMacMicrophoneAccess();
if (!macPermissionGranted) throw new Error("macOS denied microphone access. Enable OpenWork in System Settings > Privacy & Security > Microphone, then restart OpenWork.");
const stream = await navigator.mediaDevices.getUserMedia({
audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true },
});
voiceRealtime.stream = stream;
setMicDiagnostics(stream);
for (const track of stream.getAudioTracks()) {View on GitHub (pinned to 2b7df46e8a)
Solutions
- Ensure the app is served over HTTPS or localhost (getUserMedia requires a secure context)
- Use the desktop app runtime where the media bridge is available, or grant the webview microphone permission (iframe allow="microphone")
- Connect with audioInput = false to use typed voice commands without a microphone
- Check navigator.mediaDevices existence in UI and hide/disable the mic option when absent
Example fix
// before
await connectRealtime(true);
// after
if (!navigator.mediaDevices?.getUserMedia) {
await connectRealtime(false); // typed voice commands only
return;
}
await connectRealtime(true); Defensive patterns
Strategy: type-guard
Validate before calling
if (!navigator.mediaDevices?.getUserMedia) {
toast.error("Microphone capture is not supported here. Use the desktop app or HTTPS.");
return;
} Type guard
const supportsMicCapture = (): boolean => typeof navigator !== "undefined" && !!navigator.mediaDevices?.getUserMedia;
Try / catch
try {
await connectRealtime(true);
} catch (e) {
if (e instanceof Error && e.message.includes("Microphone capture is unavailable")) {
offerTypedVoiceFallback(); // connectRealtime(false)
} else throw e;
} Prevention
- Serve the app over HTTPS or localhost (secure context requirement)
- Grant microphone permission to the webview/iframe (allow="microphone")
- Detect getUserMedia support at startup and hide mic UI when absent
- Offer a typed-command fallback mode
When it happens
Trigger: connectRealtime(audioInput = true) when navigator.mediaDevices is undefined or navigator.mediaDevices.getUserMedia is missing — e.g. the page is not served over HTTPS/localhost, or the embedded webview strips media APIs.
Common situations: OpenWork web UI accessed over plain http; running in a webview/iframe without allow="microphone"; Linux/Windows builds or CI runtimes lacking the media stack; user launched the app in a browser that blocks getUserMedia.
Related errors
- macOS denied microphone access. Enable OpenWork in System Se
- OpenWork host connection is not ready.
- Realtime offer did not include SDP.
- Failed to write .opencode/openwork.json
- Environment variable store could not be read
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/8630361aa3f97a87.
Report an issue: GitHub.