Diagnostics Catalog

The Covenant compiler uses a unified diagnostic system with three categories:

  • E-codes — errors that halt compilation
  • W-codes — warnings (compilation continues, but output may be suboptimal or risky)
  • L-codes — LSP lint detectors (IDE-only, 38+ rules, do not affect CLI build)

Diagnostic Format

All diagnostics follow the ariadne format — color-coded spans with source context:

error[E401]: type mismatch
  --> src/Token.cvt:14:20
   |
14 |     let payout = salary + bonus
   |                          ^^^^^ expected `encrypted<uint256>`, found `uint256`
   |
   = note: use `fhe_add(salary, bonus)` for homomorphic addition

All diagnostics include:

  • Code (E401, W702, L-UNR-001)
  • Message
  • Source span(s)
  • Optional note with fix suggestion
  • Optional help with documentation link

JSON Format (for tooling)

covenant check --format json ./src/Token.cvt
{
  "diagnostics": [
    {
      "code": "E401",
      "severity": "error",
      "message": "type mismatch",
      "span": { "file": "src/Token.cvt", "start": [14, 20], "end": [14, 25] },
      "note": "use fhe_add(salary, bonus) for homomorphic addition"
    }
  ]
}

E-Codes — Errors

E100–E199: Lexer Errors

CodeNameDescription
E101UnexpectedCharacterInvalid byte in source file
E102UnterminatedStringString literal not closed before end of line
E103InvalidEscapeUnrecognized escape sequence in string
E104OverflowLiteralInteger literal too large for any Covenant type
E105InvalidHexLiteralMalformed hex literal (odd number of digits)
E110InvalidUnicodeCodepoint\u{...} escape out of valid Unicode range

E200–E299: Parser Errors

CodeNameDescription
E201UnexpectedTokenToken not valid at current parse position
E202MissingClosingBraceUnmatched {
E203InvalidFieldTypeType expression could not be parsed
E204DuplicateFieldTwo fields with the same name in one contract
E205DuplicateActionTwo actions with the same name
E206InvalidGuardPlacementGuard clause not at start of action
E207EmptyContractContract body has no fields or actions
E210DesugarFailedDesugaring rule precondition not met
E220InvalidAmnesiaBlockamnesia { } contains non-destructible constructs

E300–E399: Resolver Errors

CodeNameDescription
E301UndefinedNameIdentifier not declared in any enclosing scope
E302AmbiguousNameName resolves to multiple declarations
E303CircularDependencyImport cycle detected
E304UnresolvedImportuse path not found
E305SelfImportContract imports itself
E310PrivateFieldAccessExternal access to private field
E311ImmutableWriteWrite to an immutable (const) field
E320BuiltinShadowUser-defined name shadows a built-in

E400–E499: Typechecker Errors

CodeNameDescription
E401TypeMismatchExpression type incompatible with context
E402EncryptedToPlaintextImplicit E-domain to P-domain coercion
E403PlaintextToEncryptedContextUnencrypted value in encrypted-only context
E404InvalidFHEOperandFHE opcode applied to non-encrypted value
E405PQKeyImmutableAttempt to reassign a pq_key field
E406AddressZeroLiteral address(0) used where disallowed
E410AmountOverflowConstant amount arithmetic overflows uint256
E411NegativeAmountamount type cannot be negative
E420UnitMismatchMixing incompatible amount units
E430InvalidEventFieldEvent field type cannot be indexed (too large)
E440ReturnTypeMismatchAction return type does not match declaration

E500–E599: Privacy Flow Errors

CodeNameDescription
E501DomainViolationE-domain value flows to P-domain output
E502RevealWithoutAuthreveal missing authorization guard
E503AmnesiaEscapeAttemptA-domain field accessed after DESTROYED phase
E504UnauthorizedDecryptfhe_decrypt called without validator auth
E505SelectiveDisclosureScopeselective_disclosure used outside authorized action
E510CrossContractDomainLeakExternal call passes E-domain to non-ERC-8227 contract
E511EventDataLeakE-domain value emitted in event data

E600–E699: IR Builder Errors

CodeNameDescription
E601InfiniteLoopUnbounded loop without exit condition
E602StackOverflowEstimated stack depth exceeds EVM limit (1024)
E603ContractSizeExceededGenerated bytecode exceeds 24 KB (EIP-170)
E604InvalidPhiPhi node has wrong number of predecessors
E610FHEDepthLimitMultiplication depth exceeds BFV capacity (requires bootstrapping)
E620AmnesiaPhaseViolationA-domain operation outside valid ceremony phase

E800–E899: Backend / Codegen Errors

CodeNameDescription
E801UnsupportedOpcodeIR opcode not supported by selected backend
E802PrecompileUnavailableRequired precompile not available on target chain
E803ABIEncodingErrorABI encoding of type not possible
E810AsterFeatureUnavailableFeature requires Aster Chain (not EVM)
E811WASMUnsupportedFeature not yet supported in WASM backend

E900–E999: Internal Compiler Errors

CodeNameDescription
E999InternalErrorCompiler bug — please report with covenant bug-report

W-Codes — Warnings

W300–W399: Resolver Warnings

CodeNameDescription
W301ShadowingName shadows an outer scope declaration
W302UnusedImportImported name never used
W303UnusedFieldField declared but never read or written

W400–W499: Typechecker Warnings

CodeNameDescription
W401ImplicitConversionWidening conversion applied implicitly
W410UnusedReturnValueAction return value discarded at call site

W500–W599: Privacy Warnings

CodeNameDescription
W501RevealToAllreveal field to all exposes encrypted state globally
W502AmnesiaExternalCallExternal call inside on_destroy hook (reentrancy risk)
W503PartialDestructionamnesia block has fields not listed in any destroy()

W700–W799: Optimizer Warnings

CodeNameDescription
W701UnreachableCodeBranch that can never be taken
W702ConstantFieldField only ever assigned once (consider const)
W703ExpensiveGasPatternDetected pattern with known high gas cost
W710FHEDepthExceededMultiplication depth near BFV limit
W711FHEBatchMissedAdjacent FHE ops not batched (optimizer limitation)

L-Codes — LSP Lint Detectors

The LSP runs 38 lint detectors in the IDE. These never block compilation but appear as squiggles/hints.

Security Lints (L-SEC-*)

CodeDescription
L-SEC-001Missing only guard on state-modifying action
L-SEC-002Unchecked external call return value
L-SEC-003Reentrancy risk: external call before state update
L-SEC-004Unrestricted destroy() outside ceremony
L-SEC-005pq_signed missing on high-value action (> 1M token threshold)
L-SEC-006admin field can be changed by admin itself (no 2-step transfer)
L-SEC-007FHE multiplication depth > 6 (bootstrapping cost warning)
L-SEC-008Hardcoded address (should use a field)
L-SEC-009Missing ReentrancyGuard on action with external call
L-SEC-010Integer division before multiplication (precision loss)

Privacy Lints (L-PVT-*)

CodeDescription
L-PVT-001Event emits encrypted value without confidential flag
L-PVT-002reveal without time-lock or deadline
L-PVT-003Selective disclosure to all (defeats privacy)
L-PVT-004Map key (address) exposed in events
L-PVT-005Cross-contract domain leak potential

Style Lints (L-STY-*)

CodeDescription
L-STY-001Action name should be snake_case
L-STY-002Field name should be snake_case
L-STY-003Contract name should be PascalCase
L-STY-004Missing description on public action
L-STY-005Magic number (use named constant)
L-STY-006Redundant given true guard
L-STY-007Empty amnesia { } block

Gas Lints (L-GAS-*)

CodeDescription
L-GAS-001map<address, bool> for whitelists (use set<address>)
L-GAS-002Unnecessary storage read in loop
L-GAS-003String error message (use typed error instead)
L-GAS-004Event emission in loop (high gas risk)
L-GAS-005fhe_encrypt inside loop

Correctness Lints (L-COR-*)

CodeDescription
L-COR-001Comparison with address(0) without null check
L-COR-002Overflow-unsafe arithmetic in unchecked block
L-COR-003Missing zero-check on amount parameter
L-COR-004Action callable during ceremony DESTROYED phase
L-COR-005on_destroy hook modifies state after destroy()
L-COR-006total_supply updated but not mirroring balances sum
L-COR-007Guard relies on block.timestamp (miner-manipulable, ±15s)
L-COR-008Self-transfer allowed (may inflate event logs)

Suppressing Diagnostics

// Suppress a specific warning for one line
#[allow(W301)]
let shadow = outer_name

// Suppress for an entire action
#[allow(W702, L-GAS-001)]
action expensive_init() only deployer { ... }

Using #[allow(...)] on an E-code is a compile error — errors cannot be suppressed.

See Also