tinyhumansai/openhuman · error · VoiceNotCompiledError

voice_not_compiled

voice_not_compiled

Error message

Voice transcription is unavailable in this build — the voice module was not compiled into the app. Update OpenHuman to the latest version; restarting will not help.

What it means

VoiceNotCompiledError (code 'voice_not_compiled') is thrown by transcribeCloud() when the JSON-RPC call to openhuman.voice_transcribe (or sibling voice_* method) fails with an 'unknown method' error. That response means the running core binary was compiled without the `voice` Cargo feature, so the voice controllers were never registered. As the comment explains, this is a compile-time property of the binary — restarting cannot fix it (the historical case: voice shipped missing from v0.58.19 to v0.61.x, issue #4901).

Solutions

  1. End user: update OpenHuman to the latest version — the fixed builds forward the voice feature again; restarting the current version will not help.
  2. Developer building the core: ensure the voice feature is enabled (product-features set) — check `scripts/ci/product-features.txt` forwarding and the Feature Forwarding Gate.
  3. Renderer: catch VoiceNotCompiledError (code 'voice_not_compiled') and hide/disable the voice UI with the 'update required' message instead of surfacing a raw failure.
  4. Verify with GET /schema on the core's RPC port that voice.* namespaces are listed before enabling voice features.

Example fix

// before
const text = await transcribeCloud(blob);

// after
try {
  const text = await transcribeCloud(blob);
} catch (err) {
  if (err instanceof VoiceNotCompiledError) {
    renderVoiceDisabledNotice(); // 'Update OpenHuman' UI
    return;
  }
  throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { callCoreRpc } from '../services/coreRpcClient';

// probe once at startup: does the core expose voice methods?
const voiceAvailable = await callCoreRpc<{ methods: string[] }>({ method: 'openhuman.schema' })
  .then((s) => s.methods.some((m) => m.startsWith('openhuman.voice_')))
  .catch(() => false);

Type guard

function isVoiceNotCompiledError(e: unknown): boolean {
  return e instanceof Error && (e as { code?: string }).code === 'voice_not_compiled';
}

Try / catch

try {
  text = await transcribeCloud(blob);
} catch (err) {
  if (isVoiceNotCompiledError(err)) {
    renderVoiceDisabledNotice(); // 'Update OpenHuman' — restart won't help
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: The renderer calls callCoreRpc({method:'openhuman.voice_stt_transcribe'...}) against a core whose DomainSet/feature set omitted voice — e.g. a custom --no-default-features build, a distro/CI build missing the voice feature flag, or a version range where voice was accidentally not forwarded to the desktop shell (the #4901 regression).

Common situations: Users on app versions v0.58.19–v0.61.x where the voice gate was not forwarded to the shell; developers building openhuman-core manually without the voice feature; a slim/embedded core profile (DomainSet without voice) being reused by the full desktop renderer.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/e420f837f6bc777e. Report an issue: GitHub.

Appendix: source

Thrown at app/src/features/human/voice/sttClient.ts:122

  const rpcStart = Date.now();
  let result: CloudTranscribeResult;
  try {
    result = await callCoreRpc<CloudTranscribeResult>({
      method: 'openhuman.voice_cloud_transcribe',
      params,
    });
  } catch (err) {
    // An "unknown method" error means the core serving this app was built
    // without the `voice` Cargo feature, so the `openhuman.voice_*`
    // controllers were never registered (#4901). This is a compile-time
    // property of the binary — restarting cannot change it, which is why the
    // old #1289-era "restart to pick up the latest core sidecar" copy was
    // unactionable (and the sidecar itself is gone since #1061).
    const msg = err instanceof Error ? err.message : String(err);
    if (msg.includes('unknown method')) {
      sttLog('[voice-stt] transcribe rpc: voice domain absent from core build: %s', msg);
      throw new VoiceNotCompiledError();
    }
    sttLog('transcribe rpc failed (passthrough): %O', err);
    throw err;
  }
  const text = result?.text?.trim() ?? '';
  sttLog('transcribed chars=%d rpc_ms=%d', text.length, Math.round(Date.now() - rpcStart));
  return text;
}

interface FactoryTranscribeOptions {
  /** BCP-47 language hint, e.g. `'en'`. */
  language?: string;
  /** Override the server-side provider resolution: `'cloud'` for the backend
   *  proxy, or a `voice_providers` slug. When unset the core resolves
   *  `voice_server.stt_engine`. */
  provider?: string;
  /** Model id for the selected engine (e.g. `'whisper-1'`, `'scribe_v1'`). */
  model?: string;

View on GitHub (pinned to 7491200858)