Skip to content

Error Handling

Achronyme provides detailed error messages across all execution modes. Errors include source location information when available.

When running with ach run, the VM reports errors with line numbers:

[line 5] in main: DivisionByZero
ErrorCause
DivisionByZeroDivision or modulo by zero
IntegerOverflowi60 arithmetic overflow (no silent promotion)
TypeMismatchIncompatible types in operation (e.g., Int + Field)
ArityMismatchWrong number of arguments to a function
AssertionFailedassert(expr) evaluated to false
OutOfBoundsArray index out of range
StackOverflowCall stack exceeded 65,536 entries (likely infinite recursion)
StackUnderflowInternal error — pop from empty stack
InvalidOpcodeCorrupt bytecode — unknown instruction
FunctionNotFoundClosure or function reference is invalid
ProveBlockFailedError during prove {} execution
ProveHandlerNotConfiguredprove {} used without --ptau
SystemErrorInternal VM state corruption

Achronyme uses 60-bit signed integers (range: -2^59 to 2^59 - 1). Overflow is always an error:

let big = 576460752303423487 // 2^59 - 1 (max i60)
let overflow = big + 1 // ERROR: IntegerOverflow

To work with larger values, use 0p field literals for BN254 field elements (e.g., 0p42, 0pxFF).

Integer and field values cannot be mixed directly:

let x = 42
let y = 0p10
let z = x + y // ERROR: TypeMismatch

Use 0p literals for explicit conversion: let z = 0p42 + y.

Syntax errors include line and column information:

parse error at line 3, col 10: expected expression

When compiling circuits with ach circuit, the IR lowering phase reports errors with source spans:

ErrorCause
UndeclaredVariableVariable used without public/witness declaration
UnsupportedOperationOperation not available in circuit mode (e.g., print)
TypeNotConstrainableNon-field type used in circuit (string, map, etc.)
UnboundedLoopLoop without fixed bounds (circuits require static unrolling)
WrongArgumentCountBuiltin called with wrong arity
DuplicateInputSame variable declared twice
IndexOutOfBoundsArray access beyond array length
ArrayLengthMismatchArray size doesn’t match type annotation
RecursiveFunctionRecursive call detected (not allowed in circuits)
TypeMismatchExpression type doesn’t match annotation
AnnotationMismatchDeclared type conflicts with inferred type

Some errors include user-friendly guidance:

// Using a string in a circuit:
"cannot be used in circuits (circuits operate on field elements only)"
// Using a map in a circuit:
"cannot be used in circuits (use arrays instead)"
// Using a decimal:
"field arithmetic is integer-only — use whole numbers"

Errors during constraint generation:

R1CS compilation error: [3:5] undeclared variable 'x'

The [line:col] prefix maps to the source location when available.

When using compile_ir_with_witness(), the IR evaluator validates inputs before constraint generation:

ErrorCause
MissingInputRequired circuit input not provided
DivisionByZeroDivision by zero with concrete values
AssertionFailedassert(expr) fails with provided inputs
AssertEqFailedassert_eq(a, b) fails — values don’t match
RangeCheckFailedValue doesn’t fit in declared bit width
NonBooleanMuxConditionmux condition is not 0 or 1
UndefinedVarInternal error — SSA variable not computed

These errors include the concrete values that caused the failure, making debugging easier:

assert_eq failed: x (= 42) != y (= 43)

After circuit compilation, the taint analysis pass checks for potential soundness issues:

witness input 'secret' is under-constrained (not in any assert_eq)

A declared input is not used in any constraint. This means a malicious prover could set it to any value without affecting the proof. This is almost always a bug.

public input 'unused_var' is unused

A declared input is never referenced in the circuit body. Remove the declaration or use the variable.

Errors inside prove {} blocks are categorized by pipeline phase:

PhaseError
IR loweringParsing or AST→IR conversion failed
CompilationConstraint generation failed
VerificationGenerated witness doesn’t satisfy constraints
Proof generationGroth16/PlonK proving failed

Example:

prove block error: IR lowering: undeclared variable 'x'

Most circuit failures come from wrong input values. The --inputs flag requires exact field-level precision:

Terminal window
ach circuit my_circuit.ach --inputs "a=42,b=7"

If a circuit fails after optimization, try running without it:

Terminal window
ach circuit my_circuit.ach --no-optimize --inputs "a=42,b=7"

Always review taint analysis output. An UnderConstrained warning often indicates a missing constraint that could allow a malicious prover to forge proofs.

In VM mode, use print() to inspect values:

let h = poseidon(1, 2)
print("hash:", h)

After compiling a circuit, verify the witness with snarkjs:

Terminal window
snarkjs r1cs info circuit.r1cs # check constraint count
snarkjs wtns check circuit.r1cs witness.wtns # verify witness

If you suspect GC-related bugs:

Terminal window
ach run program.ach --stress-gc

This triggers garbage collection on every allocation, exposing rooting issues.