Troubleshooting
Find the symptom, confirm the cause, apply the fix. Every error the runtime raises names what failed; start with the exception type.
Installation#
| Symptom | Cause | Fix |
|---|---|---|
pip install helixor-runtime finds no package | The package is not on the public index yet. | Install the wheel from your evaluation access. See Installation. |
| Import crashes on Python 3.14 | 3.14 is not yet supported. | Use Python 3.11 or 3.12, the verified versions. |
pip install fails with "requires a different Python: … not in '>=3.11'" | Changed in 0.3.0: the wheel declares Python 3.11 or later. Earlier wheels declared 3.9 but failed at import on it. | Use Python 3.11 or 3.12. |
SalesEngineUnavailableError (SALES_ENGINE_NOT_IN_RUNTIME) when you use HelixorSalesEngine | Changed in 0.3.1: the sales engine is not part of the runtime. It ran Helixor's own sales playbook, which is not distributed, so in 0.3.0 it always failed with FileNotFoundError. | Write your decisions as a playbook, compile it with helixor-pack compile and load it with HelixorEngine.load_pack(). See Add custom rules. |
| Process aborts on import on macOS with an OpenMP "duplicate library" message | Two numeric libraries in the environment each load their own OpenMP runtime. | Use a clean virtual environment. As a stopgap, set KMP_DUPLICATE_LIB_OK=TRUE. |
ModuleNotFoundError: fastapi or websockets | Service dependencies missing from a trimmed environment. | Reinstall the runtime with its dependencies. |
Licenses#
| Error | Cause | Fix |
|---|---|---|
LicenseSignatureInvalidError | The file was edited, truncated, re-encoded, or is not a Helixor license. | Use the file exactly as issued. Check line endings if it passed through a secret store. |
LicenseExpiredError | Past valid_until plus the grace period, or the host clock is wrong. | Renew, then recompile or re-download packs. Check the host's time sync. |
LicenseNotYetValidError | Before valid_from, usually a clock running behind. | Fix time sync. |
LicenseEntitlementError | The license does not cover the pack ID or a solver the pack uses. | helixor-pack inspect-license and compare its pack patterns with the pack ID. |
LicenseNotFoundError; the CLI prints Error: LICENSE_NOT_FOUND: no Helixor license file was found. and exits 1 | No license in any of the six locations the message lists: the explicit path, HELIXOR_LICENSE_FILE, ./helixor.hxlic, ./helixor.lic, ~/.helixor/helixor.hxlic, ~/.helixor/helixor.lic. Or an explicit path or HELIXOR_LICENSE_FILE names a file that does not exist. | Save your license as ~/.helixor/helixor.hxlic with mode 600, pass --license / license_file=, or set HELIXOR_LICENSE_FILE. To get a license, request one on the sign-up page; the CLI cannot mint or sign one. |
LicenseLocationAmbiguousError (LICENSE_LOCATION_AMBIGUOUS) | One directory holds both helixor.hxlic and the older helixor.lic. The runtime does not guess which to use. | Keep one file, preferably helixor.hxlic, or pass the license explicitly. |
helixor-pack: error: argument command: invalid choice: 'mint-license' | Changed in 0.3.1: the CLI cannot mint or sign licenses. | Licenses are issued by Helixor; request one on the sign-up page. |
Packs#
| Error | Cause | Fix |
|---|---|---|
PackUnsealError: content key mismatch | The pack was compiled for a different license, or before a renewal. | Recompile or re-download with the license you are running. |
PackUnsealError: bad magic, version or integrity | Truncated or corrupted file, or not a pack. | Re-fetch the artifact and compare its SHA-256 with the one you recorded at build time. |
CompilerError: mapping values are not allowed here | An unquoted value containing : in the playbook. | Quote the value. See Playbooks. |
FileNotFoundError from HelixorEngine.load_pack | The pack does not exist at the path given, or no license was found. A missing license raises LicenseNotFoundError, which is also a FileNotFoundError and lists the locations checked. | Fix the path, or put your license where the message says. load_pack never falls back to the built-in pack. |
UnsupportedPackDeclarationError at compile or load | The playbook declares something a compiled pack does not execute: your own codons or hard_rules, a rule type other than regex or luhn_checksum, an action other than block or redact, a rule without id, or an invalid pattern. | Read the listed problems; express the logic as supported rules. See Playbooks. |
RemovedCapabilityError from compile_custom_rule | Changed in 0.3.0: the method is removed from HelixorEngine, on every engine. | Add the rule to the playbook's rules and compile again. |
UnsupportedPackDeclarationError at compile, or PackDeclarationUnsealError at load: "actions does not declare …" | The playbook lists actions but leaves out an action the pack can return, often the built-in ones. | List every action named in the error, or omit actions, and compile again. See Playbook schema. |
DecisionBudgetExceededError | A decision took longer than the pack's budget.max_latency_ms. The result is withheld. | Treat it as no decision. Raise the budget if it is tighter than your host can meet. |
Evaluation#
| Symptom | Cause | Fix |
|---|---|---|
| Several triggers, but the action names only one rule | Every match is reported; the first fatal match decides the action. By design. | Explain with action and reason; report everything found from triggers. |
CodonRuntimeError from evaluate() on a dict | The dict has no text, message or payload key, or its value is not a string. | Pass a string, or put the text under one of those keys. See Evaluating decisions. |
AmbiguousPayloadError from evaluate() on a dict | The dict has more than one key, so evaluating one field would leave the others unchecked. | Pass the text as a string, or a dict with exactly one of text, message, payload. |
LicenseExpiredError from evaluate() on a running compiled pack | The license passed its grace period while the process was running. | Deploy a renewed license and packs recompiled for it. |
| A 16-digit number is not treated as a card | It fails the Luhn check. | Expected. Use a real test number such as 4111-1111-1111-1111. |
DeveloperQuotaExceededError | Per-minute or lifetime limit reached on a Developer license whose overage policy is not TRUE_UP. The built-in example pack and compiled packs both enforce the limits. | Slow down, or move to a tier without limits. |
Wall-clock time is much higher than latency_us | latency_us covers evaluation only. The first call in a process is also slower. | Measure end to end; warm the engine at startup with one clean evaluation. |
Streaming and services#
| Symptom | Cause | Fix |
|---|---|---|
| The last words of a stream never arrive | flush() was not called. | Call session.flush() when the source ends. |
StreamBlockedError: Stream blocked by statutory invariant | A fatal rule fired inside stream_filter or astream_filter. | Expected; catch it and end the response. |
ServerConfigurationError: Refusing to bind '0.0.0.0' without authentication | A non-loopback host without a service token. | Pass --token or set HELIXOR_SERVICE_TOKEN, or bind 127.0.0.1. |
401 Missing or invalid bearer token | The service has a token and the request did not send it. | Send Authorization: Bearer <token>. GET /v1/health needs no token. |
400 "per-request license_key is not accepted" | The service serves a compiled pack; a request cannot bring its own license. | Drop license_key from the request. |
| Browser calls fail with a CORS error | Cross-origin access is off by default. | List the origin in HELIXOR_CORS_ORIGINS. A wildcard is rejected. |
WebSocket error with code STREAM_BLOCKED | A stream_chunk after a blocked token. Changed in 0.3.0: the connection stays blocked until the next stream_start. | Expected. Close the connection on blocked: true, or send stream_start to begin a new stream. |
Known issues and fixes#
Every defect documented for 0.2.1, and its status in runtime 0.3.0. Each status was checked against the released 0.3.0 wheel on 2026-09-29. Builds labelled 0.2.1 were cut from several commits, so when you report an issue against one, give the wheel's SHA-256. Rows marked "Fixed in 0.3.1" were checked against the released 0.3.1 wheel on 2026-10-02; 0.3.1 changes no other row.
Runtime#
| Issue | Affects 0.2.1 | Status in 0.3.0 |
|---|---|---|
| WebSocket stream continues after a blocked token (Services) | Yes | Fixed: later chunks get STREAM_BLOCKED until stream_start |
A blocked value can stay in a compiled pack's clean_text (Playbook schema) | Yes | Fixed: any fired block rule withholds the whole text |
| A regex rule with capturing groups reports and redacts only the first group | Yes | Fixed: the whole match is reported and redacted |
Compiled-pack receipts hash clean_text, so different inputs share a receipt (Receipts) | Yes | Fixed: one receipt recipe for both engines, over the input digest |
compile_custom_rule() has no public engine it runs on, and does not redact its match | Yes | Fixed: removed, raises RemovedCapabilityError |
evaluate(dict) evaluates one text field and ignores the rest (Evaluating decisions) | Yes | Fixed: a dict with more than one key raises AmbiguousPayloadError |
Compiled packs accept actions, default_action and budget without enforcing them | Yes | Fixed: checked at compile and load; budget.max_latency_ms checked on every decision |
Compiled packs accept invariants and remedies without executing them | Yes | Open: still accepted and not executed |
| Compiled packs do not enforce the license's per-minute and lifetime decision limits | Yes | Fixed |
Manifest merkle_root is a placeholder (Pack manifest) | Yes | Fixed: it carries the playbook's SHA-256, the same value as raw_pack_sha256 |
The contact rule's factor names one field (Pack manifest) | Yes | Open: factor is still has_email; factors lists all three |
| Package metadata does not match the code: distribution name and version | Yes | Fixed: helixor-runtime 0.3.0. Publishing to the public index is still Planned |
| The wheel declares Python 3.9 but does not import on it | Yes | Fixed: requires Python 3.11 or later, and pip refuses it on 3.9 |
The wheel does not include the sales playbook, so HelixorSalesEngine() raises FileNotFoundError | Yes | Open in 0.3.0. Fixed in 0.3.1: the sales engine is not part of the runtime, and using it raises SalesEngineUnavailableError (SALES_ENGINE_NOT_IN_RUNTIME) |
The customer CLI offers helixor-pack mint-license, and the no-license error tells you to run it | Yes | Open in 0.3.0. Fixed in 0.3.1: the command is removed; the no-license error points to the sign-up page |
| The CLI and the Python loaders search different places for the license, and the Python loaders skip the working directory | Yes | Open in 0.3.0. Fixed in 0.3.1: one search order for every entry point, canonical name helixor.hxlic |
| Importing the runtime loads the GPU solver's libraries, about 0.9 s (Benchmarks) | Yes | Fixed: import measured at 111 to 129 ms on 0.3.0 |
| Cold start above the 100 ms target | Yes | Open in 0.3.0: import alone is 111 to 129 ms. In 0.3.1 at the target, not reliably under it: import, construction and first evaluation took 86.9 to 100.2 ms, measured against the released 0.3.1 wheel on 2026-10-02 |
HelixorBeliefLedger has no snapshot or restore (Outcome memory) | Yes | Fixed: snapshot() and restore() |
| Generated Python client: caller-supplied action, one cause in the counterfactual (Python) | Yes | Fixed: the client bundled with 0.3.0 is regenerated |
Generated Python client: NativeRuntimeUnavailableError is not a HelixorRuntimeError | Yes | Open: it derives from RuntimeError only |
Generated Java sources: caller-supplied action, isApproved() false for clean payloads, every failure reported as an SSN block, placeholder merkleRoot() (Java) | Yes | Fixed in the sources that were in the demo repository's sdks/java; those sources are no longer published (removed from the repository with its 0.3.1 update). They still do not build: the runtime artifact they depend on is Planned |
Hosted reasoning service Preview#
| Issue | Affects | Status |
|---|---|---|
/v1/decide: p_correct not calibrated, abstentions reported as answers, composed built on abstained questions, require.* and unknown questions ignored (Reasoning service) | Service builds before 2026-09-28 | Fixed on main |
Learning loop: a version whose disposition_bands keys are not alphabetical becomes unreadable after a restart (Learning loop) | Service builds before 2026-09-28 | Fixed on main |
| Learning loop: built-in default golden cases and exception clause | Service builds before 2026-09-28 | Fixed on main: both come from the pack or the request |
| Playbook turn response does not name the pack version that decided | Service builds before 2026-09-28 | Fixed on main: pack_version, pack_digest, pack_source |
Playbook turn takes tenant_id from the request body; outcomes and evolve not scoped to the tenant | Service builds before 2026-09-28 | Fixed on main: tenant from your credentials, conflicting tenant refused with 403 tenant_mismatch |
Still stuck?#
Email hello@helixor.ai with the runtime version (helixor_runtime.__version__), Python version, the exception type and message, and the output of helixor-pack inspect-license (it shows no key material; remove the contact email line). Never include license files, packs or real payloads.