{"record":{"id":"b33bac039cf3730d","repo":"stablyai/orca","slug":"rpc-error-message-b33bac","errorCode":null,"errorMessage":"${RPC error message}","messagePattern":"\\$\\{RPC error message\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mobile/src/hooks/mobile-dictation-audio-chunk.ts","lineNumber":41,"sourceCode":"  const raw = event.data\n  const bytes = raw instanceof Uint8Array ? raw : new Uint8Array(raw)\n  const byteLength = bytes.byteLength\n  if (!queue.pendingAudioBudget.tryReserve(byteLength)) {\n    queue.failActiveDictation(\n      dictationId,\n      new Error(MOBILE_DICTATION_CONNECTION_SLOW_ERROR_MESSAGE)\n    )\n    return\n  }\n  const sendChunk = client\n    .sendRequest('speech.dictation.chunk', {\n      dictationId,\n      audioBase64: bytesToBase64(bytes),\n      sampleRate: MOBILE_DICTATION_PCM_SAMPLE_RATE\n    })\n    .then((response) => {\n      if (!response.ok) {\n        throw new Error(response.error.message)\n      }\n    })\n    .catch((err) => queue.failActiveDictation(dictationId, err))\n    .finally(() => {\n      if (queue.shouldReleaseBudget(dictationId)) {\n        queue.pendingAudioBudget.release(byteLength)\n      }\n      queue.pendingChunks.delete(sendChunk)\n    })\n  queue.pendingChunks.add(sendChunk)\n}\n","sourceCodeStart":23,"sourceCodeEnd":53,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/hooks/mobile-dictation-audio-chunk.ts#L23-L53","documentation":"Thrown inside the speech.dictation.chunk send promise when the host returned {ok:false} for an audio chunk. It is immediately caught by the .catch handler which calls queue.failActiveDictation(dictationId, err) — so the throw is internal control flow that routes the error into the active-dictation failure pipeline rather than bubbling to a caller.","triggerScenarios":"client.sendRequest('speech.dictation.chunk', {dictationId, audioBase64, sampleRate}) returns {ok:false}. Causes: dictationId unknown to host (session expired/canceled server-side), host transcription pipeline crashed, transport hiccup, host throttling chunks.","commonSituations":"The desktop dictation session was canceled out from under the mobile client (e.g., user started a new session elsewhere); the host speech process crashed; slow network caused the host to time out the session; chunk payload exceeded a host limit.","solutions":["Because failActiveDictation already cancels the session and surfaces the error to the UI, treat a chunk error as terminal for the current dictationId — do not retry the chunk.","After the failure UI, the user can start a fresh session (new dictationId via createMobileDictationId) which re-runs the full start handshake.","Check the desktop host speech logs for the underlying cause (session not found vs. pipeline error).","If chunk errors recur, verify the host build supports the current speech.dictation.chunk contract."],"exampleFix":"// before\n.then((response) => {\n  if (!response.ok) {\n    throw new Error(response.error.message)\n  }\n})\n.catch((err) => queue.failActiveDictation(dictationId, err))\n\n// after — include the code so the failure UI can branch on session-expired\n.then((response) => {\n  if (!response.ok) {\n    const code = response.error?.code\n    const err = new Error(response.error.message)\n    if (code) (err as any).code = code\n    throw err\n  }\n})\n.catch((err) => queue.failActiveDictation(dictationId, err))","handlingStrategy":"try-catch","validationCode":"// Only enqueue chunks when the session is active and host is connected\nif (!client || !dictationId || !enabled || !acceptingChunks) return\nif (connState !== 'connected') return","typeGuard":"function isSessionNotFound(err: unknown): boolean {\n  const code = (err as any)?.code\n  return code === 'session_not_found' || code === 'session_expired'\n}","tryCatchPattern":"// The existing pipeline already routes this into failActiveDictation;\n// callers of failActiveDictation can branch on session-not-found:\nconst failActiveDictation = (dictationId, err) => {\n  if (isSessionNotFound(err)) {\n    setError('Dictation session expired. Tap to start a new one.')\n    setStatus('idle')\n    return\n  }\n  reportError(err)\n}","preventionTips":["Stop enqueueing chunks the moment activeIdRef clears or enabledRef flips false.","Cancel the remote session on any audio interruption so the host does not send session_not_found mid-stream.","Keep the pending-audio budget tight so a slow host fails fast rather than heaping up chunks."],"tags":["rpc","dictation","speech","audio","typescript"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}