Repository navigation
Troubleshooting
Symptom → cause → fix.
Cause: no Rust toolchain on PATH. The dev and rust extras declare the native extension as
an editable path dependency, and it must be compiled.
Fix: install Rust from https://rustup.rs, or remove the khocr-gen-core entry from the
dev/rust extras in pyproject.toml and re-sync for a pure-Python environment.
Cause: you ran it from inside rust/. rust/pyproject.toml declares its own maturin project,
so a bare uv run there treats rust/ as a separate project root and creates a stray
rust/.venv — the extension lands there, not in the real environment.
Fix: pin the environment and build from the repo root:
VIRTUAL_ENV=/path/to/ocr-foundry/.venv uv run --with maturin maturin develop --release --manifest-path rust/Cargo.tomlDelete any stray rust/.venv afterward.
Cause: uv sync re-resolves and reinstalls declared dependencies every run, so it can overwrite
a hand-built maturin develop binary with its own cached build.
Fix:
uv cache clean khocr-gen-coreCause: PyYAML is required for --config/-c.
Fix: pip install pyyaml.
Cause: the font directory layout is wrong, or the pool is empty.
Fix: the root given to --fonts must contain khmer/ and/or english/ subdirectories with
.ttf/.otf/.ttc/.woff/.woff2 files (scanned recursively). Fonts placed directly in the root
join both pools as fallbacks. Check the path is what you think it is: --fonts fonts is relative to
the current working directory.
Cause: no font in the pool covers the glyphs of those lines, and the retry budget was exhausted. Khmer coverage varies a lot between fonts.
Fix: add more Khmer fonts (especially one with broad coverage), and raise --retry-limit.
Check generation_errors.jsonl in the split directory; it records render failures. See
Fonts.
Cause: bold/italic use real variant fonts. With no file tagged bold (or italic/oblique) in the pool, the decoration is skipped rather than synthesised.
Fix: add variant files such as NotoSansKhmer-Bold.ttf. Tags are detected from the filename stem
and the internal style name (bold, italic, oblique).
Cause: random text colour requires RGB output.
Fix: add --color-mode 3.
Cause: this should not happen; the renderer resizes rather than crops. If you see clipping,
suspect a custom --image-dir input or a very small explicit --height/--width combination
pushing glyphs outside the canvas at render time.
Fix: reproduce with a minimal case and file an issue with the text, font and flags. As a
workaround, use --line-height-mode variable with --font-size-mode proportional, which keeps
glyphs inside the canvas by construction.
Cause: every corpus line was filtered out by --min-length / --max-length, or the corpus file
is empty or not UTF-8.
Fix: run --count-only to see the filter statistics, and check --corpus points at the right
file.
Cause: the split ratio is 0. Setting only one of --val-percent / --test-percent forces the
other to 0.
Fix: set both, or use --split-ratios 80 10 10. See
Corpus and Normalization.
Check that the corpus, font bytes, configuration, generator/dependency versions
and output format match. generate seeds rendering and augmentation per sample
across worker counts, but a seed alone cannot compensate for different inputs
or runtimes. --seed none disables per-sample seeding. Seeded augmentation uses
Python implementations instead of native Rust. The verify preview command
has separate RNG behavior; see FAQ.
Cause: rare-character oversampling is off by default, or the percentile is too strict.
Fix: enable --oversample-rare-chars and widen --rare-char-percentile (e.g. 20). Remember val
and test are never oversampled.
Cause (most likely): a nested mapping. The loader reads flat keys only; nested mappings are skipped with a warning and the default is kept.
Fix: replace
sauvola:
prob: 0.2with
sauvola-prob: 0.2Watch stderr for Config key 'sauvola' is a nested mapping; only flat keys are supported, skipping.
(that line names the key that was dropped). A key that matches no flag warns instead with
[config] WARNING: Unrecognized keys in 'generate' configuration: …, which usually means a typo.
Note the fonts key is fonts, not fonts-dir. See Configuration.
Cause: precedence is argparse defaults < YAML < explicit CLI flags. This normally works, but values written as argparse defaults in a wrapper script can shadow the config.
Fix: pass flags directly on the command line rather than via a wrapper, or move the value into the YAML.
Cause: you set --line-height-mode variable or bucketed. --height is only used in fixed
mode.
Fix: expected. Control heights with --min-line-height / --max-line-height.
Causes and fixes, in order of impact:
-
Rust acceleration is off — check
HAS_RUST_ACCEL. Building the extension is the single biggest win. See Rust Acceleration. -
Too few workers — the default auto-resolves to
cpu_count // 2; pass--workers Nexplicitly to use more. -
Small dataset — below
2048samples generation stays serial by design. -
--font-mode all— touches every font at every standard size; much heavier thanrandom.
The font face caches are bounded (LRU, 1024 entries) and were specifically fixed to stop unbounded
growth. If you still see growth, --workers multiplies the per-process footprint; lower it, and
prefer random over all font mode. See the memory fixes in
CHANGELOG.md.
Cause: the dataset exceeds the LMDB map size (default 256 GiB is generous, but small
--lmdb-map-size-gb values or a constrained filesystem can bite).
Fix: raise --lmdb-map-size-gb, or --map-size-gb for combine.
Cause: these platforms cannot use fork.
Fix: the tool already selects spawn there. If a payload is unpicklable in your environment,
force a method explicitly:
KHOCR_GEN_MP_START_METHOD=spawn khocr-gen generate ...Cause: fork from ProcessPoolExecutor's own thread deadlocks once the parent process holds
locks (Python 3.14 warns about this). The default is therefore forkserver, not fork.
Fix: leave the default, or set KHOCR_GEN_MP_START_METHOD=spawn if a worker cannot be pickled.
fork remains available as an explicit override when you know the parent is still single-threaded.
Cause: forkserver and spawn import the script in the worker. A call at module scope starts
another pool while the child is still bootstrapping, and the real RuntimeError is hidden.
Fix: generation is refused before the pool starts unless the script has a module-level guard that can run. The check parses the file; a quoted copy of the guard, or the same if nested in a function or under if False:, still re-executes the script.
if __name__ == "__main__":
main()khocr-gen, python -c, and an interactive python -i session are already safe. To keep an
unguarded script on the old start method:
KHOCR_GEN_MP_START_METHOD=fork python your_script.pyCause: --worker-timeout (default 300 s) is too low for a heavy batch, or a worker is stuck.
Fix: raise --worker-timeout, or run serially with --workers 1 to isolate the problem.
Cause: Rust-accelerated methods keep their own thread RNG. The per-image reseeding only makes the pure-Python methods reproducible.
Fix: expected behaviour, not a bug. See Augmentation.
Cause: --min/--max are pixel heights for this method, not [0, 1] intensities.
Fix: pass pixel values, e.g. --min 16 --max 800.
Cause: --lmdb must point at the directory containing data.mdb, usually
data/<split>/lmdb, not data/ or data/<split>.
Fix: khocr-gen view --lmdb data/train/lmdb --summary.
Cause: the output directory already exists. combine will not clobber it silently.
Fix: pass --overwrite, or choose a different --output.
Cause: --skip-vocab was set.
Fix: drop the flag. The merged vocabulary covers every character across all merged splits.
Open an issue at https://github.com/0x1d1e/ocr-foundry/issues with:
- the exact command you ran,
- your config file, if you used one,
- the output of
khocr-gen --version, - for image-quality problems, a sample image plus the
verify_outputPNG for the method involved.
OCR Foundry — synthetic OCR training data with Khmer/English and opt-in multilingual rendering · MIT · Repository · Issues · PyPI · Changelog
Using OCR Foundry
Data controls
- Corpus and Normalization
- Fonts
- Variable Line Height
- Text Decorations and Effects
- Augmentation
- Output and Storage
- Page Layout
Internals
Help