Troubleshooting & FAQ#
This section addresses common issues and questions that may arise when using anira.
Frequently Asked Questions#
General#
What is anira?#
Anira is a high-performance library designed for real-time neural network inference in audio applications. It provides a consistent API across multiple inference backends with a focus on deterministic performance suitable for audio processing.
Which platforms are supported?#
Anira supports macOS, Linux, and Windows platforms. It has been tested on x86_64, ARM64, and ARM7 architectures.
Which neural network frameworks are supported?#
- Anira currently supports three inference backends:
LibTorch
ONNX Runtime
TensorFlow Lite
Note
Custom backends can be integrated as needed.
Is anira free and open source?#
Yes, anira is open source and available under the Apache-2.0 license.
Technical Questions#
How does anira ensure real-time safety?#
- Anira ensures real-time safety through several mechanisms:
No dynamic memory allocation during audio processing
Static thread pool to avoid oversubscription
Lock-free communication between audio and inference threads
Pre-allocation of all required resources
Consistent timing checks and fallback mechanisms
What’s the minimum latency I can achieve?#
The minimum achievable latency depends on several factors, including model complexity, hardware performance, and audio buffer size. Anira is optimized for low-latency operation and, in ideal conditions, can return inference results within the same audio processing cycle—effectively achieving zero added latency.
Can I use multiple models simultaneously?#
Yes, you can use multiple models simultaneously by creating separate anira::InferenceHandler instances, each with its own model configuration. All handlers can share the same thread pool, enabling efficient parallel processing of multiple models.
Troubleshooting#
Compilation Issues#
Missing Backend Dependencies#
Issue: CMake fails to find LibTorch, ONNX Runtime, or TensorFlow Lite.
- Solution: You can disable specific backends using CMake options:
-DANIRA_WITH_LIBTORCH=OFF
-DANIRA_WITH_ONNXRUNTIME=OFF
-DANIRA_WITH_TFLITE=OFF
-DANIRA_WITH_LITERT=OFF
-DANIRA_WITH_EXECUTORCH=OFF
Alternatively, you can specify custom paths to these dependencies if they are installed in non-standard locations.
Compilation Errors with C++ Standard#
Issue: Compiler errors related to C++ standard compatibility.
Solution: Anira requires C++17 or later. Ensure your compiler supports C++17.
Runtime Issues#
Audio Glitches or Dropouts#
Issue: Audio processing experiences dropouts or glitches during inference.
- Solutions:
Increase the maximum inference time in your
anira::InferenceConfigto allow more time for model processing.Reduce the complexity of your neural network model
Increase audio buffer size (though this increases latency)
Check if other processes are consuming CPU resources
Use anira::benchmark tools to identify performance bottlenecks
Model Loading Failures#
Issue: “Failed to load model” or similar errors.
- Solutions:
Verify the model file exists at the specified path
Check that the model format is compatible with the selected backend
Ensure tensor shapes in your
anira::InferenceConfigmatch the model’s expected shapesTry a different backend if available
Wait Strategy Mismatch#
Issue: The log shows [WARNING] ContextConfig wait strategy mismatch.
All anira instances in a process share one inference thread pool, and the pool’s threads wait for work according to the anira::WaitStrategy of the first anira::ContextConfig the context was created with. A later instance that requests a different strategy has no effect — the warning tells you the originally configured strategy stays active. This is harmless (both strategies produce identical results), but the requested idle-CPU/latency characteristic is not the one in effect.
Solution: Use the same wait_strategy in every anira::ContextConfig (and in the context_config block of every JSON configuration file) that the process loads.
Thread Priority Issues#
Issue: Thread priority settings fail, particularly on Linux.
Solution: On Linux, you may need to set the rtprio limit for your user. Add the following to /etc/security/limits.conf:
your_username - rtprio 99
Log out and back in for the changes to take effect.
Unexpected Results or Crashes#
Issue: Inference produces incorrect outputs or crashes.
- Solutions:
Validate tensor shapes in your
anira::InferenceConfigmatch your model’s expectationsEnsure your pre/post-processing logic correctly handles the data format
Try using a different backend to rule out backend-specific issues
Check that your model works correctly outside of anira use the minimal inference example provided in the Examples section.
Host application ships its own backend runtime#
Issue: A plugin embedding anira crashes (or fails to instantiate with an “OrtGetApiBase resolved to an ONNX Runtime that does not support the API version” error) inside a specific host application, but works in the standalone build and in other hosts. Ableton Live 12, for example, bundles its own ONNX Runtime dylib for its built-in AI features.
Cause: If backend symbols are exported from the plugin binary, the dynamic
linker can bind them across module boundaries — ELF interposition on Linux,
weak-symbol coalescing on macOS (e.g. the ORT C++ header’s
Ort::Global<void>::api_). The plugin’s backend calls then resolve against
the host’s (typically older) runtime and the first API call crashes the host.
- Solutions:
Use anira’s build system, which links every engine in exactly one of two shapes and keeps it private. Backend linkage follows
BUILD_SHARED_LIBS: a sharedlibaniralinks the shared engine libraries, a staticlibaniralinks the static engine archives, and an engine that does not ship the required linkage is disabled (LibTorch in static builds, ExecuTorch in shared builds). In both shapes the guarantee is the same — one copy of the engine per process, never exported. anira links its enginesPRIVATEthrough theiranira::<engine>targets (cmake/aniraBackendHelpers.cmake): the static archives are linked on demand and hidden (-load_hiddenon macOS,--exclude-libson Linux/Android; the desktop ExecuTorch archives get--exclude-libson ELF, and so does the bundled tanh-lib archivelibtanh_core.aas defense-in-depth — tanh-lib’s own components are compiled hidden with an emptyTANH_APIwhen static), and anira itself is compiled with hidden symbol visibility (tanh_apply_symbol_policy, from the sharedcmake/tanh/symbol-policy.cmake). A staticlibanirais compiled without any export decoration (ANIRA_APIis empty underANIRA_STATIC, which the CMake package defines for consumers), so a plugin that embeds it with hidden visibility exports nothing of anira. A sharedlibanirainstead pins its export table to namespaceaniraat link time (tanh_set_export_allowlist(anira NAMESPACE anira)generates the ELF version script / macOS-exported_symbols_listat configure time): compiler visibility alone cannot hide what a header stamps default-visibility itself — libstdc++’sstd::instantiations, LibTorch’sC10_APItypeinfo, or the default-visibility ExecuTorch desktop archives. anira’s ONNX Runtime processor additionally verifies at startup thatOrtGetApiBase()resolved to a compatible runtime and throws a descriptive error instead of crashing the host.If your plugin’s own translation units include engine headers (e.g.
onnxruntime_cxx_api.h), link the engine’s target —target_link_libraries(your_plugin PRIVATE anira::anira anira::onnxruntime)— and compile those translation units with hidden visibility too (CXX_VISIBILITY_PRESET hidden,VISIBILITY_INLINES_HIDDEN ON).anira::aniraalone carries no engine header, on purpose: the engine target is the same file anira links (one copy per process), and it is where the engine’s include directory lives. Weak symbols the engine headers instantiate in your objects (Ort::Global<void>::api_) are only hidden by your own visibility setting.Restrict your plugin’s exports to its entry points — e.g. on macOS
-Wl,-exported_symbols_listwith only_bundleEntry/_bundleExit/_GetPluginFactoryfor a VST3, on Linux a version script (-Wl,--version-script) with the same names underglobal:andlocal: *;(for a CLAP plugin the only name isclap_entry; with anira’s CMake package the two linestanh_apply_symbol_policy(<plugin>)andtanh_set_export_allowlist(<plugin> SYMBOL clap_entry)do all of this — seeexamples/clap-audio-plugin/CMakeLists.txt). This also covers any other statically linked dependency and is required on macOS when your plugin links a static anira with the ExecuTorch backend: its desktop archives are force-loaded, and ld64 has no hidden variant of-force_load, so nothing short of an export list keepsexecutorch::/xnn_*out of the plugin’s export table. Verify withnm -gU your_plugin(macOS) ornm -D --defined-only your_plugin.so(Linux): noOrt/backend symbols should appear. anira runs the same check on its own binaries in CTest (anira_exports,tanh_add_export_checkfromcmake/tanh/check-exports.cmake— usable for your plugin too).Optional, but it pairs with the allowlist: dead-code stripping. anira’s objects are compiled with one section per function and variable (
-ffunction-sections -fdata-sections,/Gy), and the sharedlibaniralinks with--gc-sections(ELF),-dead_strip(macOS) or/OPT:REF(MSVC). A staticlibanirahas no link step of its own, so pass the linker flag from your plugin’s build to drop everything of anira and the backends that the plugin never references.examples/clap-audio-pluginshows the complete plugin-side set: hidden visibility,-fno-gnu-uniqueunder GCC, dead-code stripping, and the export list of solution 3.
Host crashes when unloading the plugin#
Issue: A plugin embedding anira works, but the host crashes when the last instance is removed or when the host quits.
Cause: Hosts unload a plugin’s shared library (dlclose / FreeLibrary)
once the last instance is gone; any thread still running inside it then executes
unmapped code. anira holds the required invariant — no anira thread exists once the
last anira::InferenceHandler is destroyed — by construction: the
inference threads exist exactly while handler instances exist, and destroying the
last one stops and joins them before its destructor returns. The context’s state is
never destroyed while the library is loaded (calling into anira is valid at any time,
even from late-running static destructors) and is reclaimed at unload.
- Solutions:
Host unloads with a live instance (a host bug, but it happens): on Linux and macOS a library-unload hook calls
anira::Context::shutdown()automatically. On Windows nothing that runs atDLL_PROCESS_DETACHmay join a thread (loader lock), so callanira::Context::shutdown()from your module-exit entry point — CLAPdeinit, VST3ExitDll— asexamples/clap-audio-plugindoes. It is idempotent and cheap when there is nothing to do.You manage inference threads yourself (
ContextConfig(0)+anira::Context::make_inference_thread()): stop them before your library can be unloaded; the hook only joins anira’s own pool.The library silently never unloads (GCC/Linux): glibc never unloads an object that defines an
STB_GNU_UNIQUEsymbol, which GCC emits for exported inline statics and template statics. anira compiles with-fno-gnu-unique; add the same flag plus hidden visibility (CXX_VISIBILITY_PRESET hidden,VISIBILITY_INLINES_HIDDEN ON) to your plugin’s translation units, and verify withnm -DC your_plugin.so | grep ' u '(should print nothing).macOS never unloads your plugin (the opposite problem, and harmless): dyld does not unload images that use thread-local storage, which the statically linked backend archives (ONNX Runtime, LiteRT, ExecuTorch) do. Such a plugin — or a
libanira.dylibwith a static backend inside — stays mapped until the host quits and cannot crash this way; anira’stest/contracts/unloadskips its unmapped assertions in that configuration.
The scenario is covered by anira’s host-shaped test/contracts/unload test, which loads a
plugin-shaped module from an executable that does not link anira, unloads it and
checks that it was really unmapped.
Note
If you continue to experience issues feel free to file an issue on the [GitHub repository](https://github.com/anira-project/anira/issues).