Tenor errors fall into four categories: elaboration errors (compile-time, from the six-pass elaborator), evaluation errors (runtime, from the evaluator), operation errors (runtime, from operation execution), and migration errors (from contract version migration). Every error is structured and machine-readable.
Error Structure
All elaboration errors share a common structure:
pub struct ElabError {
pub pass: u8, // 0-6: which pass failed
pub construct_kind: Option<String>, // e.g., "Fact", "Rule", "Entity"
pub construct_id: Option<String>, // e.g., "score", "approve_order"
pub field: Option<String>, // e.g., "type", "initial", "stratum"
pub file: String, // source file path
pub line: u32, // source line number
pub message: String, // human-readable error message
}When serialized to JSON (as in conformance suite expected-error.json files), the structure is preserved exactly. The pass field tells you which elaboration stage failed, which narrows the cause immediately.
Pass 0/1: Lex, Parse, Bundle Assembly
Pass 0 (lexing) and Pass 1 (parsing + bundle assembly) handle source text processing, file loading, import resolution, and cross-file construct merging. These errors indicate problems with file access, syntax, or multi-file contract structure.
cannot open file '{path}'
Cause: The elaborator could not read the specified file. The file does not exist, is not readable, or the path is malformed.
Fix: Verify the file path. Check file permissions. If this is an imported file, check the import path in the importing file.
error[pass 0]: cannot open file 'contracts/shared/types.tenor'
--> main.tenor:2import cycle detected
Cause: File A imports file B, which (directly or transitively) imports file A. The elaborator tracks the import stack and detects cycles with O(1) lookups using a parallel HashSet.
Fix: Break the cycle. Extract shared constructs (typically TypeDecl definitions) into a separate type library file that both files import. Type library files cannot themselves contain import declarations.
error[pass 1]: import cycle detected
--> contracts/order.tenor:1
note: import stack: main.tenor -> order.tenor -> shared.tenor -> order.tenorcannot resolve import '{path}'
Cause: The import path does not resolve to an existing file. The path is relative to the importing file's directory.
Fix: Check the import path spelling. Verify the file exists at the expected location relative to the importing file.
error[pass 1]: cannot resolve import 'shared/common_types.tenor'
--> contracts/main.tenor:3import '{path}' escapes the contract root directory
Cause: An import path attempts to reference a file outside the contract root directory (the directory containing the entry-point .tenor file). This is a sandbox violation --- contracts cannot reach outside their root.
Fix: Move the imported file inside the contract root directory, or restructure your contract layout so all files are descendants of the entry point's directory.
error[pass 1]: import '../../secrets/keys.tenor' escapes the contract root directory
--> contracts/main.tenor:2duplicate {kind} id '{id}': first declared in {file}
Cause: Two different source files declare a construct of the same kind with the same identifier. Construct identifiers must be unique within their kind across the entire bundle. For example, two files both declaring fact order_amount is an error.
Fix: Rename one of the duplicates, or consolidate the declaration into a single file.
error[pass 1]: duplicate Fact id 'order_amount': first declared in shared/facts.tenor
--> contracts/order.tenor:5type library files may not contain import declarations
Cause: A file that contains only TypeDecl constructs (a type library file) also contains an import statement. Type libraries are leaf nodes in the import graph --- they provide shared types but cannot import other files.
Fix: Remove the import statement from the type library file. If the type library needs types from another file, merge them into a single type library.
error[pass 1]: type library files may not contain import declarations
--> shared/types.tenor:1unterminated block comment
Cause: A /* ... */ block comment was opened but never closed before the end of the file.
Fix: Add the closing */ for the block comment.
error[pass 0]: unterminated block comment
--> contracts/main.tenor:42expected '{token}', got '{token}'
Cause: The parser expected a specific token (keyword, delimiter, or operator) but encountered something else. This is a general syntax error.
Fix: Check the syntax at the indicated line. Common causes: missing braces, missing commas, misspelled keywords, incorrect nesting.
error[pass 1]: expected '}', got 'rule'
--> contracts/order.tenor:28Pass 2: Construct Indexing
Pass 2 builds HashMap-based indexes for fast construct lookup. It detects within-file duplicates (Pass 1 catches cross-file duplicates).
duplicate {kind} id '{id}': first declared at line {line}
Cause: The same file declares two constructs of the same kind with the same identifier. This is a same-file duplicate, distinct from the cross-file duplicate caught in Pass 1.
Fix: Rename one of the duplicates or remove the redundant declaration.
error[pass 2]: duplicate Rule id 'check_compliance': first declared at line 15
--> contracts/rules.tenor:42Pass 3: Type Environment
Pass 3 extracts all TypeDecl constructs, detects cycles, and builds the type environment (HashMap<String, RawType>) that maps type names to resolved base types.
TypeDecl cycle detected: {A} -> {B} -> {C} -> {A}
Cause: TypeDecl definitions form a circular reference chain. Type A references type B, which references type C, which references type A. The error message includes the full cycle path.
Fix: Break the cycle by inlining one of the type references. TypeDecl is a convenience alias --- it must resolve to a concrete BaseType tree with no cycles.
error[pass 3]: TypeDecl cycle detected: Address -> Location -> Address
--> contracts/types.tenor:8Pass 4: Type Resolution and Expression Checking
Pass 4 has two phases. Pass 4a replaces all TypeRef(name) nodes with concrete RawType trees. Pass 4b type-checks all predicate expressions in rules and operations: fact reference resolution, operator compatibility, numeric promotion, and multiplication safety.
unknown type reference '{name}'
Cause: A TypeRef in a Fact declaration, Rule payload, or Record field references a type name that does not exist in the type environment. The name was never declared as a TypeDecl.
Fix: Add a TypeDecl for the referenced name, or correct the spelling.
error[pass 4]: unknown type reference 'OrderStatus'
--> contracts/facts.tenor:12
field: type
construct: Fact 'current_status'unresolved fact reference: '{name}' is not declared
Cause: A predicate expression references a fact by name, but no Fact construct with that identifier exists in the contract.
Fix: Declare the fact, or correct the fact reference name in the rule or operation precondition.
error[pass 4]: unresolved fact reference: 'order_total' is not declared
--> contracts/rules.tenor:18
construct: Rule 'check_threshold'operator '{op}' not defined for Bool
Cause: A comparison expression applies an operator to a Bool-typed value that Bool does not support. Bool values support only = and !=. Ordering operators (<, <=, >, >=) are not defined for Bool.
Fix: Use = or != for Bool comparisons. If you need ordering semantics, consider using an Enum or Int representation instead.
error[pass 4]: operator '>' not defined for Bool
--> contracts/rules.tenor:22
construct: Rule 'priority_check'operator '{op}' not defined for Text
Cause: A comparison applies an ordering operator (<, <=, >, >=) to a Text-typed value. Text supports only = and !=. Tenor does not define lexicographic ordering on text.
Fix: Use = or != for Text comparisons. If you need ordering, map the text to an Enum or Int in the external system before asserting as a Fact.
operator '{op}' not defined for Enum
Cause: A comparison applies an ordering operator to an Enum-typed value. Enums support only = and !=. Enum variants have no inherent ordering.
Fix: Use = or != for Enum comparisons. If you need ordering semantics, use a separate Int or Decimal fact that encodes the ordering numerically.
variable * variable multiplication is not permitted
Cause: A predicate expression multiplies two variable references (fact references or verdict payload references). Tenor only permits variable * literal multiplication. Variable-by-variable multiplication is forbidden because it can produce unbounded range expansion that defeats static analysis.
Fix: Replace one of the variables with a literal value, or restructure the computation so the multiplication happens in the external system before fact assertion.
error[pass 4]: variable * variable multiplication is not permitted
--> contracts/rules.tenor:30
construct: Rule 'calculate_fee'type error: product range {range} not contained in declared verdict payload type {type}
Cause: A multiplication expression in a Rule's produce clause produces an Int result whose range (computed from the operand ranges) exceeds the declared verdict payload type's Int range. This is a static overflow check.
Fix: Either widen the verdict payload type's Int range to contain the product range, or narrow the input fact's range so the product fits.
error[pass 4]: type error: product range Int(-1000000, 1000000) is not contained
in declared verdict payload type Int(0, 100000)
--> contracts/rules.tenor:35
construct: Rule 'compute_score'Pass 5: Structural Validation
Pass 5 performs deep structural validation across all construct types. It is the most comprehensive pass, with dedicated validators for entities, rules, operations, flows, sources, systems, and parallel steps.
Entity Errors
initial state '{state}' is not declared in states: [{states}]
Cause: The entity's initial field names a state that is not in the entity's states list.
Fix: Either add the initial state to the states list, or change initial to reference an existing state.
error[pass 5]: initial state 'new' is not declared in states: [pending, active, closed]
--> contracts/entities.tenor:5
construct: Entity 'order'
field: initialtransition endpoint '{state}' is not declared
Cause: A transition references a state (as source or destination) that is not in the entity's states list.
Fix: Add the missing state to the states list, or correct the transition endpoint spelling.
error[pass 5]: transition endpoint 'archived' is not declared
--> contracts/entities.tenor:12
construct: Entity 'order'
field: transitionsEntity cycle detected: {A} -> {B} -> {C} -> {A}
Cause: The entity parent DAG contains a cycle. Entity A declares B as parent, B declares C, and C declares A. The entity hierarchy must be a directed acyclic graph.
Fix: Remove one of the parent references to break the cycle. Re-examine the entity hierarchy design.
error[pass 5]: Entity cycle detected: Order -> LineItem -> Order
--> contracts/entities.tenor:20Rule Errors
stratum must be a non-negative integer; got {value}
Cause: A rule's stratum field is negative or not an integer.
Fix: Set the stratum to 0 or a positive integer. Stratum 0 rules have no verdict dependencies. Higher strata can reference verdicts from lower strata.
unresolved VerdictType reference: '{name}'
Cause: A rule's predicate references a verdict type (via verdict_present()) that is not produced by any rule in the contract.
Fix: Declare a rule that produces the referenced verdict type, or correct the verdict type name.
error[pass 5]: unresolved VerdictType reference: 'ComplianceApproval'
--> contracts/rules.tenor:28
construct: Rule 'final_check'stratum violation: rule at stratum N references verdict from stratum N
Cause: A rule at stratum N references a verdict produced by another rule also at stratum N. Rules can only reference verdicts from strictly lower strata. This enforces the stratification guarantee: no circular verdict dependencies.
Fix: Move the referenced rule to a lower stratum, or move the referencing rule to a higher stratum.
error[pass 5]: stratum violation: rule at stratum 1 references verdict from stratum 1
--> contracts/rules.tenor:35
construct: Rule 'secondary_check'
note: 'RiskScore' is produced by 'calculate_risk' at stratum 1Verdict Uniqueness (S8)
If two or more rules produce the same VerdictType name, the contract is statically rejected during Pass 5. This enforces S8 (verdict uniqueness). Use distinct VerdictType names for each rule and, if needed, a higher-stratum aggregation rule.
Operation Errors
allowed_personas must be non-empty
Cause: An operation declares an empty allowed_personas list. Every operation must be invocable by at least one persona.
Fix: Add at least one persona to the allowed_personas list.
undeclared persona '{name}'
Cause: An operation's allowed_personas list references a persona that is not declared as a Persona construct in the contract.
Fix: Declare the persona, or correct the persona name spelling.
error[pass 5]: undeclared persona 'admin'
--> contracts/operations.tenor:15
construct: Operation 'approve_order'
field: allowed_personaseffect references undeclared entity '{name}'
Cause: An operation's effect list references an entity that is not declared in the contract.
Fix: Declare the entity, or correct the entity name in the effect.
error[pass 5]: effect references undeclared entity 'Invoice'
--> contracts/operations.tenor:22
construct: Operation 'ship_order'
field: effectsduplicate outcome '{name}'
Cause: An operation declares two outcomes with the same label. Outcome labels must be unique within an operation.
Fix: Give each outcome a distinct label.
Flow Errors
entry step '{name}' is not declared in steps
Cause: The flow's entry field names a step that does not exist in the flow's steps map.
Fix: Add the entry step to the flow, or change the entry to reference an existing step.
error[pass 5]: entry step 'start' is not declared in steps
--> contracts/flows.tenor:8
construct: Flow 'order_flow'
field: entryOperationStep must declare a FailureHandler
Cause: An OperationStep in a flow does not declare a failure handler. Every OperationStep must specify what happens on failure: either terminate (abort the flow) or compensate (run a sequence of compensating operations).
Fix: Add a on_failure: terminate or on_failure: compensate { ... } clause to the OperationStep.
error[pass 5]: OperationStep must declare a FailureHandler
--> contracts/flows.tenor:18
construct: Flow 'order_flow'
field: steps.process_paymentNote: OperationStep outcome routing must also be exhaustive --- every declared outcome of the referenced operation must have a routing target. Missing outcome routes are also caught in Pass 5.
Source Errors
source '{id}' with protocol '{protocol}' is missing required field '{field}'
Cause: A Source declaration uses a core protocol (http, database, graphql, grpc) but is missing a required field for that protocol. For example, an HTTP source requires base_url; a database source requires dialect.
Fix: Add the missing required field.
| Protocol | Required Fields |
|---|---|
http | base_url |
database | dialect |
graphql | endpoint |
grpc | proto_ref |
static | (none) |
manual | (none) |
error[pass 5]: source 'order_api' with protocol 'http' is missing required field 'base_url'
--> contracts/sources.tenor:5
construct: Source 'order_api'invalid extension protocol tag '{tag}'
Cause: An extension protocol tag does not match the required format: x_[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*. Extension tags must start with x_ followed by a lowercase identifier, optionally with dot-separated segments.
Fix: Correct the tag format. Valid examples: x_internal, x_custom.event_bus, x_acme.legacy.mainframe.
unknown protocol tag '{tag}'
Cause: A Source declaration uses a protocol tag that is neither a core protocol (http, database, graphql, grpc, static, manual) nor a valid extension tag (starting with x_).
Fix: Use one of the six core protocol tags, or use an x_-prefixed extension tag for custom protocols.
System Errors
System validation (enabled when the contract contains system constructs) checks cross-contract composition constraints:
- Member ID uniqueness (C-SYS-01): Each member in a system must have a unique identifier.
- Shared persona existence (C-SYS-06): Personas listed in
shared_personasmust be declared in the referenced member contracts. - Trigger reference validity (C-SYS-07 through C-SYS-12): Trigger source/target flows must exist in the referenced member contracts, with valid outcome references and persona references.
- Shared entity state set equality (C-SYS-14): Entities listed in
shared_entitiesmust have identical state sets across all member contracts sharing them. - Trigger graph acyclicity (C-SYS-15): The trigger graph (flows triggering other flows across contracts) must be acyclic.
Parallel Errors
Parallel step validation ensures that branches in a ParallelStep do not have overlapping entity effect sets. Two branches that both transition the same entity type create a conflict that cannot be resolved atomically.
Evaluation Errors (EvalError)
Evaluation errors occur at runtime when the evaluator processes facts, evaluates rules, or executes predicates.
MissingFact
Fields: fact_id
Cause: A required fact was not provided in the FactSet and has no declared default value. The evaluator cannot proceed without this value.
Fix: Provide the fact value in the FactSet, or add a default value to the Fact declaration in the contract.
TypeMismatch
Fields: fact_id, expected, got
Cause: The value provided for a fact does not match the fact's declared type. For example, providing a string where an Int is expected, or providing an enum value not in the declared variant set.
Fix: Provide a value matching the declared type. Check the fact's type declaration.
Overflow
Fields: message
Cause: A numeric computation exceeded the fixed-point decimal range (28 max significant digits). This can occur during multiplication or addition in predicate expressions.
Fix: Narrow the input ranges in your fact declarations, or restructure the computation to avoid large intermediate values.
InvalidOperator
Fields: op
Cause: An operator was applied that is not supported for the operand types. This should be caught at elaboration time (Pass 4), but can surface at runtime with dynamic type resolution.
UnknownFact
Fields: fact_id
Cause: A predicate expression references a fact that does not exist in the assembled FactSet. Distinct from MissingFact --- this means the fact ID itself is unrecognized, not just absent.
UnknownVerdict
Fields: verdict_type
Cause: A predicate references a verdict type via verdict_present() that was not produced by any rule. In a well-typed contract this should not occur, but can surface when evaluating against a partial or modified bundle.
TypeError
Fields: message
Cause: An expression type error at runtime. For example, attempting field access on a non-Record value, or tag mismatch on a TaggedUnion (accessing a variant that does not match the active tag).
ListOverflow
Fields: fact_id, max, actual
Cause: A list fact value contains more elements than the declared max bound.
Fix: Ensure the source system provides lists within the declared maximum length, or increase the List's max bound in the contract.
InvalidEnum
Fields: fact_id, value, variants
Cause: An enum fact value is not one of the declared variant values.
Fix: Provide a value from the declared enum variant set, or add the new variant to the Enum type declaration.
NotARecord
Fields: message
Cause: A field access expression (.field_name) was applied to a value that is not a Record type.
UnboundVariable
Fields: name
Cause: A variable referenced inside a forall or exists quantifier is not bound by that quantifier. The variable name is not in scope.
Fix: Check the quantifier binding. The variable must be declared in the quantifier's binding clause.
FlowError
Fields: flow_id, message
Cause: A flow execution failed. This is a wrapper for errors that occur during flow step execution, including operation errors, sub-flow errors, and step routing failures.
Operation Errors (OperationError)
Operation errors occur when executing a specific operation during a flow.
PersonaRejected
Fields: operation_id, persona
Cause: The persona attempting to invoke the operation is not in the operation's allowed_personas set. This is the first check in the execution sequence (step 1 of 5).
Fix: Either invoke the operation with a persona that is in allowed_personas, or add the persona to the operation's allowed_personas list in the contract.
PreconditionFailed
Fields: operation_id, condition_desc
Cause: The operation's precondition predicate evaluated to false against the current frozen snapshot (FactSet + VerdictSet). This is step 2 of the execution sequence.
Fix: Ensure the required facts and verdicts are present and have values that satisfy the precondition before invoking the operation. Use dry-run evaluation (tenor dry-run) to test preconditions without side effects.
InvalidEntityState
Fields: entity_id, instance_id, expected, actual
Cause: The operation's effect declares a transition from state expected, but the targeted entity instance is currently in state actual. The transition source does not match the current state.
Fix: Verify the entity is in the expected state before invoking the operation. This often indicates a race condition in concurrent execution or an incorrect flow design.
EntityNotFound
Fields: entity_id, instance_id
Cause: The operation targets an entity instance that does not exist in the EntityStateMap. The (entity_id, instance_id) pair has no entry.
Fix: Ensure the entity instance has been created (E15) and is included in the EntityStateMap (E17) before invoking operations that target it.
Migration Errors (MigrationError)
Migration errors occur when analyzing or executing contract version migrations.
Diff(DiffError)
Cause: The structural diff between two interchange bundles failed. The bundles could not be compared.
Deserialize(String)
Cause: One of the interchange bundles could not be deserialized from JSON. The bundle file may be malformed or truncated.
Analysis(String)
Cause: The compatibility analysis between two contract versions failed. This can occur when the change taxonomy encounters an unexpected construct structure.
StateMismatch
Fields: entity_id, instance_id, expected, found
Cause: During migration execution, an entity instance was expected to be in a specific state (per the migration plan) but was found in a different state. Another operation may have modified the entity between plan creation and execution.
Fix: Re-run migration analysis against the current state, or ensure no concurrent operations modify entities during migration.
Storage(String)
Cause: The storage backend reported an error during migration execution. This is an infrastructure error --- check database connectivity, permissions, and disk space.
Incompatible(String)
Cause: A breaking change was detected and no migration policy was declared. The migration cannot proceed without an explicit policy for how to handle the breaking change.
Fix: Provide a migration policy via tenor migrate --policy or address the breaking changes in the new contract version. See the migration taxonomy for change classification details.