Exit codes¶
Opencomplai uses fixed, contractual exit codes so CI pipelines can reliably gate merges and deployments.
| Code | Constant | When it happens |
|---|---|---|
0 | PASS | All critical controls passed. |
1 | CONTROL_FAIL | One or more critical controls failed (e.g. an Annex III high-risk use case, or a failed pipeline evaluator), or a gated framework has a failing row (see Gating other frameworks). |
2 | VALIDATION_FAIL | Input or manifest validation failed (e.g., missing or invalid system-manifest.json, or a bad gate setting), or check --sign was given and no signing key exists (no key file and no SIGNING_KEY_PRIVATE). |
3 | POLICY_BLOCK | A prohibited (Article 5) practice was detected in the declared purpose, e.g. social scoring, or the manifest's checker verdict is prohibited_practice. Also returned by check in service-backed mode (OPENCOMPLAI_API_URL set) when the service cannot be reached. |
4 | TRAP_DETECTED | Article 25 substantial-modification trap: the change makes you a provider. Raised locally by --change-context model_retrain, purpose_change or capability_extension, and by the risk engine in service-backed mode. |
Which frameworks gate¶
The EU AI Act always gates check: its rules, the checker verdict, evaluators and the code scan set the result as described above. Any other target framework gates only when opencomplai.yaml gate.frameworks or check --gate lists it, and then only by turning PASS into CONTROL_FAIL (exit 1) when one of its rows is Missing (or, with fail_on: partial, Partial). A gated framework never produces exit 3 or 4 and never halts the system. gaps, report and recommend never gate, whatever the targets. See Frameworks.
High-risk acceptance¶
An acceptance record acknowledges the Art. 6 high-risk classification. It does not state that the system is compliant and it removes no other obligation, so Missing EU AI Act rows still fail the check. Without a record, check behaves as before.
| Case | Exit | failed_controls |
|---|---|---|
| Not accepted (no record) | 1 | EU_AIA_ART6_HIGH_RISK, unchanged |
| Accepted, no Missing EU rows | 0 | EU_AIA_ART6_HIGH_RISK is gone |
| Accepted, Missing EU rows | 1 | the Missing article ids, such as Art. 9; the Art. 6 row is not counted |
| Stale or invalid record (edited manifest, unsigned, tampered, untrusted) | 1 | EU_AIA_ART6_HIGH_RISK, with a warning on stderr |
A prohibited (Article 5) result is always 3, whatever the record. A valid trap approval for the same --change-context, together with a valid acceptance, replaces exit 4 with the accepted-path result above and does not halt the system; without both, exit 4 and the halt are unchanged. An approval alone is not honoured.
Typical CI usage¶
- name: Compliance check
run: opencomplai check
# Step fails automatically on exit code 1, 2, 3, or 4.
Remediation¶
| Exit code | Action |
|---|---|
1 | Review failed rules in the human output. Fix the compliance gap, then re-run. |
2 | Run opencomplai init first, or check that system-manifest.json is valid. For check --sign, create a key with opencomplai init, set SIGNING_KEY_PRIVATE, or use --sign-if-available to write an unsigned artifact. |
3 | The system as declared is a prohibited practice under Article 5. Review the intended purpose with your compliance team; it cannot be placed on the EU market as described. |
3 (service) | The service could not be reached in service-backed mode. Check that the service is running and that OPENCOMPLAI_API_URL points at it; see service connectivity errors. |
4 | The system is halted pending review (see below). Complete the provider obligations for the modified system, then approve and resume. |
Control register (opencomplai controls)¶
opencomplai controls status mirrors the same exit-code convention for the persistent control register (requires OPENCOMPLAI_VAULT_URL):
| Exit code | When it happens |
|---|---|
0 | Every control is satisfied or waived, and none are stale by TTL. |
1 | A control is evidence_missing (unless --no-fail-on-missing), evidence_stale, pending_review, or stale by TTL. |
2 | OPENCOMPLAI_VAULT_URL is not set, or an input (control id, file path) was invalid. |
3 | The evidence-vault request failed (network/service error). |
controls list and controls assign/attach-evidence always exit 0 on success — only status gates CI.
Halt / resume gate (opencomplai check, opencomplai docs generate)¶
When check detects a trap (TRAP_DETECTED), or an unresolved HIGH-risk corroboration gap (HIGH risk class plus a failed --scan --fail-on ... gate), the system is persisted as HALTED_PENDING_REVIEW. While halted, opencomplai docs generate for that system_id refuses with exit 4 and no dossier is written — there is no --force bypass. Resume with opencomplai approve --system-id ... --approver ... to mint a signed approval token, then opencomplai resume --system-id ... --approval-token ...; an invalid or mismatched token exits 2 and leaves the system halted.
Fail-closed dossier gate (opencomplai docs generate)¶
docs generate also exits 2 (VALIDATION_FAIL) — separately from the halt gate above — when the generated Annex IV dossier itself fails schema validation (a HIGH-risk dossier missing required Section 2-9 content or provider attestations). The dossier is still written to disk (or persisted server-side by the doc-generator service, which returns HTTP 422 for the same case) so an auditor can see what failed; only the exit code communicates failure. Pass --allow-incomplete (CLI) or allow_incomplete: true (service request body) to restore the old always-succeed behaviour, e.g. for a CI pipeline that only wants the dossier artifact and gates completeness separately. See docs generate.