Errors and Warnings
The Jac compiler uses a structured diagnostic code system. Every error, warning, and note has a unique code that identifies the issue and can be used for inline suppression.
Diagnostic codes follow the pattern {severity}{category}{sequence}:
- Severity:
E (error) or W (warning)
- Category digit:
0 = syntax, 1 = type, 2 = semantic, 3 = lint, 4 = import, 5 = codegen, 9 = internal
- Sequence: Three-digit number within the category
For example, E1030 is a type error about attribute access, and W3005 is a lint warning about empty parentheses.
Guide Pointers
When a diagnostic maps to a topic covered by the bundled reference guides, jac check prints a one-line pointer beneath it:
error[E1001]: Cannot assign Literal["hello"] to int
--> example.jac:2:5
→ run 'jac guide jac-types' for guidance
Run the suggested command for the relevant reference material. See jac guide.
Suppressing Diagnostics
Inline Suppression
Add a # jac:ignore[CODE] comment on the same line as the diagnostic to suppress it:
x = some_func(); # jac:ignore[E1030]
Multiple codes can be suppressed on the same line:
x = some_func(); # jac:ignore[E1030,W2001]
Project-Level Suppression
Use jac.toml to suppress diagnostics project-wide. See the Configuration reference for lint rule configuration.
CLI Flags
--nowarn on jac check suppresses all warnings (errors are still shown)
-e / --diagnostics on jac run controls diagnostic verbosity: error (default -- fail on errors with full details), all (errors + warnings), or none (silent)
Syntax Errors (E0xxx)
Emitted by the parser and lexer during source code parsing.
Token Expectation
| Code |
Message |
E0001 |
Expected '{expected}', got '{got}' |
E0002 |
Missing '{token}' |
E0003 |
Expected identifier, got '{got}' |
E0004 |
Unexpected token in expression: '{got}' |
E0005 |
Unexpected token '{token}' |
E0006 |
Unexpected token |
Keyword Restrictions
| Code |
Message |
E0010 |
'{keyword}' is not supported in Jac |
E0011 |
Jac does not allow this keyword in any syntactic position |
E0012 |
Use the new(target, ...args) ambient builtin to create new instances |
E0013 |
'{keyword}' is a keyword and cannot be used as a {context} name |
Operator / Expression Errors
| Code |
Message |
E0020 |
Walrus operator ':=' requires a simple name on the left side |
E0021 |
Expected :<+ or :+> to close connect operator |
E0022 |
Expected ':' or '{' after lambda parameters |
E0023 |
Expected augmented assignment in for...to...by step |
Statement-Level Errors
| Code |
Message |
E0030 |
Unexpected semicolon at module level |
E0031 |
Module-level 'with' blocks only support 'entry', not 'exit' |
E0032 |
Unexpected '{token}' -- must follow its parent statement (if/try/match/switch) |
E0033 |
'{modifier}' is not a valid prefix modifier |
E0034 |
Expected 'with' after 'can' ability name (use 'def' for function-style declarations) |
Block / Body Requirements
| Code |
Message |
E0040 |
try statement requires at least one except or finally block |
E0041 |
match statement requires at least one case |
E0042 |
switch statement requires at least one case |
E0043 |
enum body must contain at least one member |
E0044 |
import statement must specify at least one item |
E0045 |
Expected literal (INT, FLOAT, or STRING) as mapping pattern key |
E0046 |
Unexpected token in archetype body |
E0047 |
Expected '{' or 'by' for impl body |
Parameter List Errors
| Code |
Message |
E0050 |
Duplicate '{param}' in parameter list |
E0051 |
'{first}' must appear before '{second}' in parameter list |
Property Declaration Errors
| Code |
Message |
E0080 |
Property declarations cannot have an initializer (declare backing storage as a separate has field) |
E0081 |
Property declaration must contain at least one of getter, setter, deleter |
Parser Warnings
| Code |
Message |
W0060 |
Docstrings in Jac go before the declaration, not inside the body |
W0061 |
Parenthesized filter syntax (?:...) is deprecated. Use bracket syntax [?:...] instead. |
W0062 |
'root()' is deprecated. Use bare 'root' instead. |
W0063 |
JSX spread {...expr} is JS-idiomatic. Prefer {**expr} in Jac. |
Lexer Errors
| Code |
Message |
E0100 |
Unterminated string literal |
E0101 |
Unterminated block comment |
E0102 |
Unterminated f-string |
E0103 |
Unterminated inline Python block |
E0104 |
Unexpected end of JSX content |
E0105 |
Unexpected character: '{ch}' |
E0106 |
Unexpected character in JSX tag: '{ch}' |
E0107 |
Lexer stuck at EOF in mode |
Type Errors (E1xxx)
Emitted by the type checker and type evaluator.
Assignment / Return Mismatches
| Code |
Message |
E1001 |
Cannot assign {actual} to {expected} |
E1002 |
Cannot return {actual}, expected {expected} |
E1003 |
Return type annotation required when function returns a value |
E1004 |
Function '{name}' declared return type {ret_type} but may implicitly return None |
E1001/E1002 with any on the right-hand side
A common trigger for E1001 and E1002 is Jac's strict gradual-typing rule: in .jac source, an any value cannot silently flow into a declared non-any, non-object destination. Ways to clear it -- type the source (e.g. has reports: list[T] on a walker, .pyi stub on a Python utility), drop the annotation (x = src() makes x inferred-any), annotate any explicitly (x: any = src()) and narrow before downstream use, or re-type at the use site with the as cast (src() as list[T]) when you know more than the checker. See The any Type and Gradual Typing.
Operator Errors
| Code |
Message |
E1010 |
Operator "{op}" not supported for type "{type}" |
E1011 |
Unsupported operand types for {op}: {left} and {right} |
Iterability / Callable
| Code |
Message |
E1020 |
Cannot unpack non-iterable |
E1021 |
Type "{type}" is not iterable |
E1022 |
Type {type} is not iterable (no __iter__ method) |
E1023 |
Type "{type}" is not callable |
Attribute Access
| Code |
Message |
E1030 |
Type "{base_type}" has no attribute "{attr}" |
E1031 |
Cannot access attribute "{attr}" for type "{type}" |
E1032 |
Type is Unknown, cannot access attribute "{attr}" |
E1033 |
Member "{member}" not found on type "{type}" |
E1034 |
Cannot perform assignment comprehension on type "{type}" |
E1035 |
Type "{src}" is not assignable to type "{dest}" |
Subscript / Await
| Code |
Message |
E1040 |
Type "{type}" is not subscriptable |
E1041 |
Type "{type}" is not awaitable |
Function Call Errors
| Code |
Message |
E1050 |
Not all required parameters were provided in the function call: |
E1051 |
Too many positional arguments |
E1052 |
Named argument '{name}' does not match any parameter |
E1053 |
Cannot assign {actual} to parameter '{name}' of type {expected} |
E1054 |
No matching overload found for the function call with the given arguments |
E1055 |
No matching overload found for method "{method}" with the given arguments |
E1056 |
Positional only parameter '{name}' cannot be matched with a named argument |
E1057 |
Parameter '{name}' already matched |
TypeVar Errors
| Code |
Message |
E1060 |
TypeVar "{name}" must be assigned to a simple variable |
E1061 |
TypeVar name "{name}" must match the assigned variable name "{var}" |
E1062 |
TypeVar "{name}" is already in use by an outer scope |
E1063 |
TypeVar() requires a string literal as the first argument |
E1064 |
TypeVar requires at least two constrained types |
E1065 |
Type variable "{name}" has no meaning in this context |
Callable Type Errors
| Code |
Message |
E1070 |
Callable requires at least one type argument for return type |
E1071 |
First argument to Callable must be a list of types or ellipsis |
E1072 |
Callable requires a return type as second argument |
E1073 |
Callable accepts only two type arguments: parameter types and return type |
Variance Errors
| Code |
Message |
E1080 |
Contravariant type variable cannot be used in return type |
E1081 |
Covariant type variable cannot be used in parameter type |
Exception / Context Manager / Yield
| Code |
Message |
E1090 |
Cannot raise {type} (not an exception type) |
E1091 |
Type {type} cannot be used in 'with' statement (no __enter__ method) |
E1092 |
Type {type} cannot be used in 'with' statement (no __exit__ method) |
E1093 |
Cannot yield {actual}, expected {expected} |
E1094 |
Visit target must be a node type, got |
E1095 |
Field '{field}' declared 'by postinit' is never assigned in {arch}.postinit |
Connection Type Errors
| Code |
Message |
E1096 |
Connection left operand must be a node instance |
E1097 |
Connection right operand must be a node instance |
E1098 |
Connection type must be an edge instance |
E1099 |
Cannot access attribute "{attr}" for type "{type}"; attribute is missing from |
Type Warnings
| Code |
Message |
W1036 |
Generic type "{type}" used without type arguments, defaulting to "{type}[Any]"; consider adding explicit type arguments |
W1050 |
Unknown intrinsic JSX element '<{tag}>' |
W1051 |
Expression type could not be resolved (Unknown) |
W1052 |
JSX component '{component}' uses an untyped props bag (props: any); its JSX props cannot be type-checked |
Import Warnings (W1xxx)
| Code |
Message |
W1100 |
Module not found |
W1101 |
Cannot import name '{name}' from module '{module}' |
W1102 |
Imported name '{name}' from foreign-source module '{module}' typed as Any |
W1103 |
'{name}' is ambient and does not need to be imported from '{module}' |
W1104 |
Use the lowercase any keyword instead of importing Any from typing |
Semantic Errors (E2xxx / W2xxx)
Emitted by static analysis and declaration-implementation matching passes.
Static Analysis
| Code |
Message |
W2001 |
Name '{name}' may be undefined |
W2002 |
Unreachable code detected |
W2003 |
'{name}' is defined but never used |
Semantic Errors
| Code |
Message |
E2004 |
Non default attribute '{name}' follows default attribute |
E2005 |
Missing "postinit" method required by uninitialized attribute(s) |
W2006 |
'@classmethod' decorator is not recommended in '{kind}' definitions |
W2007 |
'@staticmethod' is not supported in '{kind}' definitions |
E2008 |
Invalid target for context update: |
Declaration-Implementation Matching
| Code |
Message |
E2009 |
Implementation could not be matched to a declaration |
W2010 |
Abstract ability {name} should not have a definition |
E2011 |
Parameter count mismatch for ability |
E2012 |
From the declaration of |
JSX Slot Body Rules
Emitted by ViewLowerPass when a {...} JSX slot's statement-template body violates the body-shape rules. See the components tutorial for the underlying model.
| Code |
Message |
E2019 |
A JSX slot renders template content and cannot 'return' a value. Use 'skip;' for slot early-exit, or move the value-producing expression outside the JSX slot. |
E2020 |
Bare 'return;' is not allowed inside a JSX slot -- it reads like it exits the enclosing function, but a slot body is an inlined IIFE. Use 'skip;' for slot early-exit. |
E2021 |
'{kw}' is not allowed inside a '{loop}' loop in a JSX slot. Use 'continue' to skip an iteration, or 'skip;' to exit the whole slot. |
E2022 |
'finally' is not allowed on a 'try' that has an 'awaiting' clause. The dispatched-but-not-joined window and finalization semantics are ambiguous together; move cleanup into an explicit mount/unmount hook or drop one of the clauses. |
E2023 |
Redundant '{...}' slot wrapping inside a JSX slot body -- slot bodies are already in slot mode. Drop the outer braces: write '<kw> ... { ... }' directly instead of '{<kw> ... { ... }}'. |
E2024 |
'has' is not allowed inside a JSX slot body. A slot body is a statement template that re-runs on every render; declaring reactive state there would compile to a conditional 'useState' and violate React's rules of hooks. Declare 'has'-fields at the component scope (the enclosing 'def -> JsxElement' body). |
E2025 |
A 'has'-field of type 'Ref[...]' must be constructed with an initializer: write '= Ref()' for a DOM ref, or '= Ref(initial)' for a value ref. It lowers to React's 'useRef', so a bare declaration has no ref object to hold -- '.current' would never be defined. This mirrors how every other 'has'-field carries a value. |
W2019 |
'while' loop in a JSX slot renders JSX without a 'key' attribute -- add 'key=' so siblings keep their identity across re-renders. |
W2020 |
'awaiting' is not yet implemented on the '{target}' target -- the 'awaiting' clause body will be ignored at runtime. Only the 'cl' (react/preact) target currently lowers 'awaiting' to a Suspense fallback. |
W2021 |
'for' loop in a JSX slot renders JSX without a 'key' attribute -- annotate one child element with 'key=' so iteration siblings keep their identity across re-renders. |
Lint Rules (W3xxx / E3xxx)
Emitted by jac lint. Rules can be configured in jac.toml. The kebab-case name in brackets is used for jac.toml configuration.
| Code |
Rule Name |
Message |
Group |
W3001 |
staticmethod-to-static |
@staticmethod should use 'static' keyword |
default |
W3002 |
combine-has |
Consecutive 'has' declarations can be combined |
default |
W3003 |
combine-glob |
Consecutive 'glob' declarations can be combined |
default |
W3004 |
init-to-can |
'{name}' should use Jac keyword |
default |
W3005 |
remove-empty-parens |
Empty parentheses can be removed |
default |
W3006 |
remove-kwesc |
Unnecessary keyword escape on '{name}' |
default |
W3007 |
hasattr-to-null-ok |
hasattr() should use null-safe access |
default |
W3008 |
simplify-ternary |
Ternary can be simplified |
default |
W3009 |
remove-future-annotations |
'from __future__ import annotations' is unnecessary |
default |
W3010 |
fix-impl-signature |
Implementation signature does not match declaration |
default |
W3011 |
remove-import-semi |
Unnecessary semicolon after import |
default |
E3012 |
no-print |
Calling print() is disallowed by rule |
all |
W3020 |
unnecessary-pass |
Unnecessary 'pass' in non-empty body |
default |
W3021 |
unnecessary-else-after-return |
Unnecessary 'else' after 'return' |
default |
W3022 |
nested-if-to-elif |
Nested 'if' in 'else' can be 'elif' |
default |
W3023 |
simplify-return-bool |
if cond return True else return False can be simplified to return cond |
default |
W3024 |
repeated-condition |
Repeated condition in if/elif chain |
default |
W3025 |
identical-branches |
Identical if/else branches -- the else is redundant |
default |
W3030 |
too-many-params |
Function has {count} parameters (threshold is {threshold}) |
default |
W3035 |
is-with-literal |
Use '==' instead of 'is' when comparing to a literal |
default |
W3036 |
mutable-default |
Mutable default argument '{type}' -- use None and assign inside the function |
default |
W3037 |
unnecessary-none-return |
Unnecessary '-> None' return type annotation on '{name}'; functions without a return statement implicitly return None |
default |
W3038 |
usestate-to-has |
useState hook for '{name}' can be replaced with has {name}: {type} = {init} |
default |
W3039 |
getattr-to-null-ok |
getattr(obj, 'attr', None) should use null-safe access |
default |
W3040 |
filter-compare-tautology |
Filter comparison '{name} == {name}' is always true |
default |
W3041 |
stale-has-read |
Reactive has field '{name}' is read after being assigned in the same can with entry block |
default |
W3042 |
map-lambda-to-comprehension |
.map(lambda x -> any { return <jsx>; }) can be replaced with comprehension syntax |
default |
Codegen Errors (E5xxx / W5xxx)
Emitted during code generation, formatting, and native compilation.
Python AST Generation
| Code |
Message |
E5001 |
String literal imports are only supported in client (cl) imports |
E5002 |
{import_type} imports are only supported in client (cl) imports |
E5003 |
Archetype has no body. Perhaps an impl must be imported. |
E5004 |
Abstract ability {name} should not have a body |
E5005 |
Ability has no body. Perhaps an impl must be imported. |
E5006 |
Invalid pipe target |
E5007 |
Binary operator {op} not supported in bootstrap Jac |
E5008 |
Invalid attribute access |
E5010 |
Spawn expressions must include a walker constructor on one side |
E5011 |
Expected expression in spawn argument |
E5012 |
Expected main module to be a Module node |
W5013 |
Both sides of spawn look like walker instantiations; defaulting to right-hand |
W5014 |
Walker spawn has more positional arguments than fields |
Native Compilation
| Code |
Message |
E5020 |
Native compilation failed: |
W5021 |
C library not found: |
W5022 |
Failed to load C library '{path}': |
W5023 |
Native module not found: |
W5024 |
Failed to compile native module {path}: {error} |
W5025 |
Failed to link native module {path}: {error} |
Layout Pass
| Code |
Message |
E5030 |
Cannot compute C3 MRO for {name}: inconsistent hierarchy |
W5031 |
obj '{arch}' field '{field}' has no type annotation |
W5032 |
obj '{arch}' field '{field}' has type '{type}' which is not layout-compatible |
Bytecode Generation
| Code |
Message |
E5040 |
Unable to find AST for module |
E5041 |
Length mismatch in import names |
E5042 |
Length mismatch in async for body |
| Code |
Message |
W5050 |
Comment could not be placed precisely; emitting near end of formatted output |
E5051 |
Formatter displaced {count} comment(s) to end of file -- refusing to save |
Native IR Generation
| Code |
Message |
E5060 |
C library import declaration '{name}' must not have a body |
Language Server
| Code |
Message |
E5070 |
Error during type check: |
E5071 |
Error during formatting: |
W5072 |
Attribute error when accessing node attributes: |
Internal Compiler Errors (E9xxx)
These indicate bugs in the compiler itself. If you encounter one, please file an issue.
| Code |
Message |
E9001 |
ICE: Pass {pass_name} -- {details} |