Troubleshooting
Status: Current Last updated: 2026-09-02 07:45 EDT
Start with verbose output
batchalign3 -vvvv align ~/corpus/ -o ~/output/
Use the final error message together with the sections below.
Attach run logs to bug reports
batchalign3 logs --export
CLI-managed runs write structured logs under ~/.batchalign3/logs/.
Worker Python resolution order
When debugging which Python the CLI selects, the full resolution order is:
BATCHALIGN_PYTHONenvironment variable- Active
VIRTUAL_ENV - A sibling Python next to the binary that can import
batchalign.worker - A project
.venvdiscovered by walking up from the binary python3.12on macOS/Linux, orpythonon Windows
The CLI cannot start local workers
For local processing, the selected Python interpreter must be able to import
batchalign.worker.
Check the runtime explicitly:
$BATCHALIGN_PYTHON -c "import batchalign.worker"
If you are not using BATCHALIGN_PYTHON, run the same import test with the
Python you expect Batchalign to discover.
batchalign3: command not found
Install (or reinstall) batchalign3:
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/FranklinChen/talkbank-tools/releases/latest/download/install-batchalign3.sh | sh
If uv installed the tool but your shell still cannot find it, ensure the uv
tool bin directory is on PATH.
The daemon will not start
Check the daemon log:
cat ~/.batchalign3/daemon.log
Then force a clean restart:
batchalign3 serve stop
rm -f ~/.batchalign3/daemon.json
batchalign3 morphotag corpus/ -o output/
warning: port <N> is already in use by ...
Symptom: the auto-daemon path refuses to start with a message naming
the configured port and, when it could identify one, the process holding
it (process <pid> (<name>)), instead of spawning a daemon that would
have failed with “Address already in use”.
Cause: before spawning, the CLI probes the configured fixed port
(crates/batchalign/src/cli/daemon.rs::probe_fixed_port): a single bind
attempt, never a retry loop. If the bind fails, it sends one short
/health request. A batchalign3 daemon that answers is adopted instead of
spawning a competing process (... daemon already running on port <N> (<build>); reusing it.); anything else (a foreign service, or a
batchalign3 process that is alive but not answering /health) gets this
refusal rather than a spawn attempt that is guaranteed to fail the same
way every time.
Remediation. Free the named port, or configure a different one in
server.yaml (port: <N>). If the message names a process, kill it
(or investigate why it is holding a port batchalign3 expects to own) before
retrying.
Cache looks stale
Bypass the cache for one run:
batchalign3 --override-media-cache morphotag corpus/ -o output/
Clear cached data:
batchalign3 cache clear --yes
batchalign3 cache clear --all --yes
Runs are slow or memory-heavy
Cap workers explicitly:
batchalign3 --workers 2 morphotag corpus/ -o output/
Force CPU mode:
batchalign3 --force-cpu morphotag corpus/ -o output/
The first real worker-backed run is usually slower because models may still need to load.
Job deferred or rejected due to memory pressure
If a job fails with MemoryPressure or logs say “job deferred due to memory
pressure”, the server’s memory gate detected insufficient RAM. The gate
polls available memory for up to memory_gate_timeout_s seconds before
giving up (default 120; see default_memory_gate_timeout_s in
crates/batchalign/src/types/config/server.rs).
Common causes:
- Too many concurrent workers, reduce
max_workers_per_jobormax_concurrent_jobsin~/.batchalign3/server.yaml - Other processes consuming RAM
- Idle workers holding loaded models, the pool evicts idle workers automatically when host memory pressure rises; if eviction isn’t firing fast enough, restart the server
Quick fixes in ~/.batchalign3/server.yaml:
# Force the server to use small-machine memory budgets
memory_tier: small
# Or override individual values
memory_gate_mb: 2000 # Reduce headroom reserve
stanza_startup_mb: 3000 # Stanza actually uses ~2-3 GB
# Disable the gate entirely (not recommended for production)
# memory_gate_mb: 0
The server auto-detects a memory tier from total RAM (Small <24 GB,
Medium 24-48 GB, Large 48-128 GB, Fleet >128 GB). Use memory_tier
to override. See Worker Tuning for details.
“Cannot find audio file” or “Media conversion failed”
Cannot find audio file: The server could not locate a media file
matching the CHAT file’s stem. Audio --server jobs now require the execution
host to see the same filesystem paths as the CLI invocation. Run the CLI on the
execution host itself (or over SSH/VNC), or make sure the same corpus path is
mounted there. If the corpus root and media root differ on that host, configure
local media_mappings or pass a server-visible --media-dir. See
Media Resolution.
Media conversion failed, ffmpeg not found: MP4 (and M4A, WebM, WMA) files require ffmpeg for conversion to WAV. Install ffmpeg:
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg
# Or download from https://ffmpeg.org/download.html
After installing, restart the server (batchalign3 serve stop && serve start).
Media conversion failed, ffmpeg error: The ffmpeg conversion itself failed. Check that the source media file is not corrupted. The error message includes ffmpeg’s stderr output for diagnosis.
align / forced-alignment failures: where to look first
When align fails, the useful distinction is which stage failed:
flowchart TD
start["align failed"]
media{"Cannot find audio file\nor conversion failed?"}
caps{"Command unsupported\nor stale-build warning?"}
parse{"Per-group FA parse error\nwith group index/window?"}
generic{"Only generic missing-timings\nor unclear success/failure?"}
media -->|yes| media_fix["Fix execution-host path visibility,\nmedia_mappings, or --media-dir"]
media -->|no| caps
caps -->|yes| caps_fix["Check /health capabilities,\nserver build hash, and client/server versions"]
caps -->|no| parse
parse -->|yes| trace_fix["Re-run with --debug-dir\nand inspect traces / fallback_events"]
parse -->|no| generic
generic -->|yes| cache_fix["Bypass FA cache with\n--override-media-cache-tasks forced_alignment\nthen inspect traces again"]
generic -->|no| done["Use normal output / bug report path"]
The two most useful commands are:
batchalign3 -vvvv align \
--debug-dir /tmp/ba-debug \
--override-media-cache-tasks forced_alignment \
-o output/ \
file.cha
and, for server mode:
curl http://SERVER:8001/jobs/JOB_ID/traces | python3 -m json.tool
What to look for in the trace payload:
fa_timeline.fallback_events[]: confirms a Wave2Vec group retried with Whisper FA- empty
fallback_eventson a successful rerun, often means the run was served from FA cache rather than reproducing the failure - group index +
audio_start_ms/audio_end_ms: the exact failing window to reproduce offline
If you are debugging direct mode instead of --server, the same --debug-dir
switch enables trace capture, but the trace is exported as debug-traces.json
in the local job staging directory rather than through /jobs/{id}/traces.
Some utterances lose timing after align
If align leaves some utterances without timing bullets, or if chatter validate reports E362 (non-monotonic timestamps) on align output, the most
likely cause is overlapping speech in the transcript.
Why this happens
CHAT transcription convention places utterances in conversational order for
readability. Overlapping speech markers (&*SPK:words) interleave one
speaker’s words inside another speaker’s utterance. But in the audio, those
words occur in temporal order, which may differ from the text order.
The alignment engine uses a monotonic matcher: it can only assign timestamps
that increase through the file in text order. When text order and audio order
diverge – which is inherent in transcripts with dense &* markers – the
matcher cannot assign correct timestamps to every utterance without violating
monotonicity.
Rather than write invalid CHAT or silently corrupt timestamps, align strips
timing from the affected utterances. They appear in the output as plain
untimed text, just as they would before alignment. The surrounding utterances
retain their full word-level timing.
How to identify affected utterances
Untimed utterances have no bullet at the end of the main tier line and no
%wor dependent tier. You can find them with:
# Show main-tier lines without timing bullets
grep '^\*' output.cha | grep -v '[0-9]_[0-9]'
If the untimed utterances cluster in blocks (especially around sections with
frequent &* markers), the cause is almost certainly text/audio order
divergence.
What you can do
-
Accept partial coverage. For many workflows, having most utterances timed is sufficient. The untimed utterances are still valid CHAT – they just lack timing.
-
Reorder utterances to temporal order before aligning. If you need full coverage and the transcript has sections where conversational grouping differs from temporal order, reordering those sections will let the aligner assign timestamps to all utterances. This is the most reliable fix.
-
Use
align --beforewhen re-aligning after hand edits. This preserves existing good timing for unmodified utterances and only re-aligns the changed regions, reducing the chance of cascading timing loss.
Known high-impact patterns
-
Dense
&*markers (3+ per utterance, or long stretches where most utterances contain&*): common in aphasia protocols, conversation analysis, and multi-party recordings. These produce the largest untimed blocks. -
Hand-edited transcripts with restructured speaker turns: When a reviewer splits, merges, or reattributes ASR utterances, the resulting text order may diverge substantially from the original audio order.
-
Short backchannels (“mhm”, “yeah”, “okay”): These are often placed after the main speaker’s utterance in the transcript but occurred during it in the audio. A single misplaced backchannel can push subsequent utterances out of monotonic order.
This is a known architectural limitation of monotonic alignment, not a bug.
For moderate-overlap files, improvements to &* handling should reduce the
problem. For heavily restructured transcripts with dense overlap, a more
fundamental change (per-speaker alignment) is needed. See
Monotonicity Invariant
for the technical details and roadmap.
“Command not supported” or missing commands
If the server rejects a command (e.g., align or transcribe) with an error
like “command not supported”, the server did not detect the required Python
dependencies at startup.
Check what the server advertises:
curl http://localhost:8000/health | python3 -m json.tool
Look at the capabilities list. If the command you need is missing:
-
Check the server log for lines containing “excluding from server capabilities”, these show which commands failed the capability gate and why.
-
Verify the Python environment has the required packages installed. All core commands work out of the box with a standard install (
uv tool install batchalign3). If a dependency was removed or failed to build, the capability probe will exclude the affected command. Key dependencies:alignneedstorchandtorchaudiotranscribeneedsopenai-whispertranslateneedsgoogletransmorphotag,utseg,corefneedstanzaopensmileneedsopensmileavqineedsparselmouthandtorchaudio
All of these are included in the base
batchalign3package, including the Cantonese providers. -
Restart the server after installing missing packages, capabilities are detected once at startup:
batchalign3 serve stop batchalign3 serve start
--server seems to be ignored
That should no longer happen for audio commands. If align, transcribe, or
another audio workflow still behaves like a local-only run, double-check that:
- you actually passed
--server http://... - the target server advertises the command in
/health.capabilities - the server can see the same absolute input/output paths on its filesystem
Check remote dispatch with a command that supports it:
batchalign3 serve status --server http://yourserver:8000
batchalign3 --server http://yourserver:8000 morphotag corpus/ -o output/
“Did my long-running job die when the server restarted?”
Yes, the old in-flight process is gone. Batchalign now has a single local
in-process control plane, so restarting batchalign3 serve interrupts running
work on that server.
What survives is the persisted SQLite job state. On the next startup, recovery
reloads queued/interrupted jobs and re-dispatches resumable work. Confirm by
querying http://<server>:<port>/jobs (the public JSON endpoint; /api/jobs
is 404, that path belongs to the SPA shell).
If a job was far enough along to have durable partial state, you should see it return as queued/running after restart rather than disappearing permanently.
Submission errors
server returned 413: length limit exceeded
Symptom: batchalign3 aborts a submission with
server returned 413: length limit exceeded (or the JSON detail
contains that phrase).
Cause: The chunk’s total serialized CHAT content exceeded the server’s
max_body_bytes_mb. This only happens on remote submissions
(explicit --server http://host:port with a non-loopback host), where the
request body carries every selected file’s CHAT text. Local submissions
(the auto-daemon path or a loopback-addressed server) use
paths_mode=true and never put file contents in the body, so 413 is
structurally unreachable on the local path. See
Submission Modes
for the selection rule.
Remediation. Pick one:
-
Raise the remote server’s body limit. On the server, edit
~/.batchalign3/server.yaml:max_body_bytes_mb: 1024Then restart:
batchalign3 serve stop && batchalign3 serve start. The default is 512 MB; raise it only if your payloads genuinely exceed that. -
Submit smaller batches. Split the input set so each submission stays under the current limit.
--file-listmakes chunking trivial: write the filenames for each chunk to a separate list and submit in sequence. -
Use a local daemon instead of remote
--server. If the CLI and the server share a filesystem, dropping--serverlets the CLI use the local daemon on127.0.0.1, which bypasses the body limit entirely (path lists instead of file contents). This is the simplest fix when a fleet machine keeps the corpus on shared storage.
The CLI does not retry 413, a deterministic rejection indicates the payload itself is too large, and re-sending would waste work. See Submit-path retries for the full retry contract.
Submission silently drops chunks
Symptom (historical): A batch script reported success on every chunk but the output directory had fewer files than input, and server logs showed no trace of the missing submissions.
Cause: A transient connect-refused from the daemon during job finalization reached the CLI as an immediate error. Scripts that treated submission errors as terminal silently skipped the chunk.
Remediation. The CLI retries transient connect/timeout failures
automatically (RETRY_ATTEMPTS = 3, exponential backoff). Use a current
batchalign3 build. A non-CLI client talking directly to the REST API
must implement its own retry on connect/timeout, but must not retry
HTTP 4xx/5xx.
External service timeouts
Timeouts reaching api.rev.ai, huggingface.co, or other external providers
usually mean the host cannot reach the required service. Confirm network access
from the machine running the worker runtime.
Apple Silicon / MPS issues
If you hit GPU-specific failures, retry with CPU mode:
batchalign3 --force-cpu align corpus/ -o output/
The --force-cpu flag is the only supported way to force CPU mode at the
CLI surface. (The only BATCHALIGN_* env vars wired into CLI args are
BATCHALIGN_SERVER, BATCHALIGN_PYTHON, and BATCHALIGN_DEBUG_DIR;
there is no BATCHALIGN_FORCE_CPU env override. To pin the
behavior across runs without typing the flag, set force_cpu: true
in ~/.batchalign3/server.yaml and run via batchalign3 serve.)
“Stripped N upstream-library warnings” in the server log
You may see lines in ~/.batchalign3/server.log like:
WARN Stripped 2 Stanza control-token leak(s) from fin item 15
(stanza defect registry: Defect 4). Leaks: [...]
These are the normal signal of an active workaround, not an error. Batchalign knows about specific defects in the upstream libraries it uses (Stanza, Whisper, Apple MPS, and others) and silently corrects them in place. Every correction emits a warning so the workaround is visible in your logs.
What to do:
- If your output CHAT looks correct (check with
chatter validate path/to/output.cha): nothing. The workaround did its job. The warning is informational, it tells you “we applied a known upstream-defect workaround N times on this job.” - If
chatter validatereports errors on the output: the workaround may have missed a new variant of the defect. Please file a bug with the input file, the warning log excerpt, and the validation error, we will extend the workaround vocabulary.
The comprehensive list of known upstream defects and their registered workarounds is maintained at reference/stanza-limitations.md (for Stanza) and developer/apple-mps-workarounds.md (for Apple MPS). The engineering policy governing how we add and retire workarounds is at developer/upstream-defect-policy.md.
Capture a full debug transcript
batchalign3 -vvv morphotag corpus/ -o output/ 2>&1 | tee debug.log
Attach debug.log together with batchalign3 logs --export when filing an
issue.
Filing bug reports
Open an issue at https://github.com/FranklinChen/talkbank-tools/issues.
Attach:
batchalign3 logs --exportoutputbatchalign3 -vvv <your-command> 2>&1 | tee debug.log- Your OS, Python version, and
batchalign3 versionoutput
This page last changed: 2026-09-10 (commit 423245db). The whole book last changed: 2026-09-16 (commit 34d249d8).