praisonai-bot package. praisonai serve gateway still works exactly as documented here; for a standalone install see praisonai-bot Migration.praisonai serve gateway exits with a specific code to tell your supervisor whether to restart or stop — a misconfigured gateway should not crash-loop forever.
Quick Start
Start the gateway normally
0 on clean shutdown, 75 on transient failure (supervisor should restart), and 78 on fatal config error (supervisor should alert, not restart).Systemd service with correct restart policy
Kubernetes restart policy
Exit Code Reference
EX_TEMPFAIL) and 78 (EX_CONFIG) follow the BSD sysexits.h standard, which most Linux supervisors understand natively.
What Triggers Each Code
Fatal configuration (exit 78)
The gateway exits 78 when it detects a problem that restarting won’t fix:- Missing required dependencies (e.g. platform SDK not installed)
- Missing or unreadable
gateway.yaml - Schema-invalid
gateway.yaml(type errors, unknown keys) - Unknown / typo’d channel platform — e.g.
telegran:when you meanttelegram:. Previously warned and started; now fails closed with exit 78. - Missing
token:on a tokenful platform — thetoken:key must be present; an empty${VAR}resolution is tolerated (the channel is skipped), but a missing key is fatal. - Plugin platform not on the registry — a
platform:name that isn’t built-in, isn’t published viapraisonai.channels/praisonai.botsentry points, and isn’t registered at runtime viaregister_platform()fails closed. To validate against your custom platform, register it before callingWebSocketGateway.start_with_config(). --agentsfile with non-mapping entriesFatalConfigErrorraised by a plugin or adapter during startup
Transient failures (exit 75)
Everything else — network errors, upstream timeouts, unexpected exceptions during operation — exits 75.Common Patterns
Raise FatalConfigError from a custom plugin
Detect exit code in a shell script
Classify exits programmatically
Supervisor Configuration Reference
systemd
How It Works
The classifier (classify_exit_reason) is a pure function with no side effects. It lives in the core package so the wrapper CLI (praisonai serve gateway) and the runtime entry point (python -m praisonai.runtime) share one source of truth.
Exit Code Reference
Fatal vs Transient
classify_exit_reason(exc) applies these rules in order:
Clean exit (0):
excisNoneexcisKeyboardInterrupt(includes SIGTERM mapped toKeyboardInterrupt)excisSystemExit(0)orSystemExit(None)excisSystemExit(n)wherenis any integer — passesnthrough unchanged
78 — do not restart):
FatalConfigErrorraised explicitly anywhere in the start pathgateway.yamlmissing, empty, or schema-invalid (load_gateway_configraisesValueError)--agentsfile missing or unreadableagents:key absent or falsy in the agents YAMLagents:is not a list (e.g.agents: {name: bad})agents:list contains a non-mapping entry (e.g.agents: ["bad"]) — previously triggeredAttributeErrorand crash-looped at code 75; now correctly raisesFatalConfigErrorand exits 78- Unknown or typo’d channel platform (e.g.
telegran:) — previously warned and started; now raisesValueErrorfrom the registry-aware validator and exits 78 - Missing
token:key on a tokenful platform — previously warned; now fatal (an empty${VAR}resolution is tolerated and the channel is skipped) - Plugin
platform:not on the registry (not built-in, not an entry point, notregister_platform()d) — exits 78 - Missing required gateway dependencies at boot (e.g.
pip install praisonai[api]not run)
75 — ask supervisor to restart):
- Any
Exceptionnot matched by the rules above
Supervisor Integration
- systemd
- Kubernetes
- s6 / runit
--config for multi-bot mode:Embedding the Classifier
Useclassify_exit_reason directly when you run the gateway start path from your own code:
FatalConfigError:
Backward Compatibility
The wrapper (praisonai serve gateway) imports the exit-code symbols from praisonaiagents.gateway at startup. Two fallback rules apply:
- If
praisonaiagents.gatewayis absent (ModuleNotFoundError) or predates the protocol (missing symbols →AttributeError), the wrapper uses local sysexits.h values (0/75/78) and a minimal classifier with the same semantics. - Any other
ImportError(a broken core install) surfaces immediately — broken cores are no longer silently swallowed.
None from start(); the new int return is backward-compatible — callers that ignored the return value continue to work and see exit 0 semantics from the shell.
s6-overlay
Docker Compose
RestartForceExitStatus=75 tells systemd to restart even when Restart=on-failure would not normally trigger (e.g. the process exits quickly). Exit code 78 is NOT in RestartForceExitStatus, so systemd will not restart on fatal config errors.
Kubernetes
s6 / runit
Best Practices
Pin RestartPreventExitStatus=78 in systemd
Pin RestartPreventExitStatus=78 in systemd
gateway.yaml restarts the gateway indefinitely, burning through CPU, log storage, and pager budget.Treat exit 78 as a paging event
Treat exit 78 as a paging event
75 is normal supervisor noise — the gateway will come back. Exit 78 means a human deployed a broken config and the gateway will never come back on its own.Validate gateway.yaml in CI before rollout
Validate gateway.yaml in CI before rollout
78 at boot is cheap. A 78 caught mid-rollout after rolling out to 10 pods is not.Don't swallow FatalConfigError without re-raising
Don't swallow FatalConfigError without re-raising
FatalConfigError and not re-raising converts exit 78 back to 75 and re-enables the crash-loop.Always set RestartPreventExitStatus=78 in systemd
Always set RestartPreventExitStatus=78 in systemd
Raise FatalConfigError for unrecoverable plugin errors
Raise FatalConfigError for unrecoverable plugin errors
FatalConfigError at startup so the operator knows to fix the config before the gateway will run.Monitor for exit 78 in your alerting
Monitor for exit 78 in your alerting
78 exit in production means a deployment broke the config. Wire it to your on-call alerting so it isn’t silently swallowed by a restart loop.Exit 0 on clean shutdown
Exit 0 on clean shutdown
/drain endpoint). Supervisors that restart on any non-zero exit will leave the gateway alone after a graceful stop.Never treat exit code 78 as a transient failure
Never treat exit code 78 as a transient failure
Add RestartSec to avoid restart storms
Add RestartSec to avoid restart storms
Use FatalConfigError for missing secrets
Use FatalConfigError for missing secrets
FatalConfigError immediately rather than letting the process crash mid-run.Log the exit code in your monitoring system
Log the exit code in your monitoring system
exit_code=78 to catch config regressions in CI/CD pipelines.
