tinyhumansai/openhuman · error

audio blob is empty

Error message

audio blob is empty

What it means

Required-flag error from `openhuman memory query`. After the parsing loop, `--namespace` was never supplied. Unlike ingest (which defaults to namespace 'cli'), query deliberately has no namespace default — you must name the namespace to search explicitly.

Source

Thrown at app/src/features/human/voice/wavEncoder.ts:23

 *
 * Why this exists: the hosted STT upstream (GMI Whisper) rejects
 * Opus-in-WebM payloads with "Invalid JSON payload", and Chromium-based
 * runtimes (including the CEF webview Tauri ships) don't reliably support
 * `MediaRecorder` with MP4. WAV at Whisper's native 16kHz is the most
 * portable thing we can hand the backend without standing up an ffmpeg
 * dependency in the desktop app.
 *
 * Implementation: `OfflineAudioContext` decodes + resamples in one pass,
 * then we mix to mono and write a standard RIFF/WAVE header in front of
 * the 16-bit little-endian samples. Synchronous after the decode promise
 * resolves so we can pipe it straight into the STT client.
 */

const TARGET_SAMPLE_RATE = 16_000;

export async function encodeBlobToWav(blob: Blob): Promise<Blob> {
  if (!blob || blob.size === 0) {
    throw new Error('audio blob is empty');
  }
  const arrayBuffer = await blob.arrayBuffer();
  // `decodeAudioData` consumes the buffer, so use a copy if the caller
  // happens to reuse `blob` afterwards.
  const decoded = await decodeToBuffer(arrayBuffer.slice(0));
  const mono = mixDownToMono(decoded);
  const wav = buildWav(mono, TARGET_SAMPLE_RATE);
  return new Blob([wav], { type: 'audio/wav' });
}

/**
 * Decode arbitrary compressed audio into an `AudioBuffer` at
 * `TARGET_SAMPLE_RATE`. Uses `OfflineAudioContext` so the resample
 * happens during decode rather than via a separate render step.
 */
async function decodeToBuffer(arrayBuffer: ArrayBuffer): Promise<AudioBuffer> {
  // OfflineAudioContext requires concrete length/channels up front, but
  // `decodeAudioData` returns a buffer at the source rate. Trick: decode

View on GitHub (pinned to a221052e0d)

Solutions

  1. Add `-n/--namespace <ns>` to the query command
  2. List existing namespaces first with `openhuman memory namespaces`
  3. In scripts, fail fast when the namespace variable is empty instead of silently dropping the flag

Example fix

# before
openhuman memory query --query "hello"
# after
openhuman memory namespaces   # pick a ns, then:
openhuman memory query --namespace cli --query "hello"
Defensive patterns

Strategy: validation

Validate before calling

# bash: refuse to invoke query without a namespace
[ -n "${NS:-}" ] || { echo '--namespace is required for query' >&2; exit 2; }
openhuman memory query --namespace "$NS" --query "$Q"

Try / catch

if ! out=$(openhuman memory query "$@" 2>&1); then
  case "$out" in *"--namespace is required"*) openhuman memory namespaces >&2; exit 2;; esac
  printf '%s\n' "$out" >&2; exit 1
fi

Prevention

When it happens

Trigger: `openhuman memory query --query "hello"` (query given, namespace missing); `openhuman memory query -v`; a script that only passes -q because the author assumed the ingest default applies to query too.

Common situations: Assuming the 'cli' default from ingest carries over to query; scripts where the namespace variable is empty and the flag is conditionally skipped; exploring a fresh workspace and not knowing which namespaces exist.

Related errors


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