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.
--nowarn on jac check suppresses all warnings (errors are still shown)
-e / --diagnostics on jac run controls diagnostic verbosity: error (default -- report error-level diagnostics with full detail), all (errors + warnings), or none (silent). This flag governs what is printed, not whether the program runs. jac run still executes -- and exits 0 -- when the type checker finds errors: for example, x: int = "no"; reports E1001 under jac check but runs anyway under jac run. Only errors that stop the compiler from producing runnable code (parse/lex and codegen errors, such as a missing ;) abort a run. To gate on type errors, use jac check, which exits non-zero
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.
Emitted by JsxIntrinsicGuardPass when a mobui project (see React Native target) uses a raw HTML host tag in JSX. The guard resolves every tag name in the enclosing scope; only unresolved lowercase names are treated as HTML host elements and rejected. Uppercase components and lowercase components that resolve to an in-scope symbol are allowed. .cl.jac web-boundary files (but not .native.cl.jac files, which target React Native) and modules outside the project root are exempt; the client kind is discovered from each module's own project jac.toml, never the process cwd.
Code
Message
E1105
JSX tag '<{tag}>' is not in scope in a mobUI project; use {suggestion} instead
Fixing E1105
E1105 fires only in mobui projects ([project] client_kind = "mobui" in jac.toml). Replace the HTML tag with the suggested @jac/mobui primitive: div/section/main -> View, span/p/h1-h6 -> Text, button -> Pressable, input/textarea -> TextInput, img -> Image, ul/ol -> ScrollView. If the lowercase name is meant to be a component, import it so it resolves in scope. Web projects (client_kind unset) are unaffected -- HTML tags remain valid there.
Emitted by OwnershipCheckPass for own/imm/borrow/&/&mut bindings and in <handle> { } region opens. See Ownership & Borrowing. On the native pathway the checker is one of the required analyses: it always runs there, and error-severity findings block native codegen -- a clean check is what makes the annotations trustworthy facts for lowering (see the Ownership Fact Schema). Whether diagnostics are displayed never changes generated code; builds with and without display are bit-identical.
Code
Message
E1301
Use of '{name}' after it was moved
E1302
Conflicting mutable borrow of '{name}' while another borrow is live
E1303
Cannot mutate '{name}' while a shared borrow of it is live
E1304
'{name}' is destroyed while still borrowed
E1305
Reserved, not yet registered -- will be "Linear resource '{name}' is never consumed" once the planned linear marker lands (a linear binding must be moved exactly once; plain own is affine and may be silently dropped)
E1306
Borrow of '{name}' escapes its scope
E1307
Reference to '{name}' escapes its region
E1308
'{name}' is not sendable across a concurrency boundary
E1309
Cannot mutate '{name}' through a deep-immutable imm binding
Emitted by OwnershipCheckPass only in nogc-enforced native modules (jac nacompile --enforce-nogc, or a module matching a jac.toml [gc.enforce] pattern -- see Zero-RC ownership compilation). They make zero-RC ownership coverage a compile-time contract: every heap-typed contract position must be in the owned world, and each violation is a hard error that blocks native codegen. The {provenance} in every message states why the module is enforced (the CLI flag or the matching config pattern).
Code
Message
E1401
Heap-typed {position} '{name}' has no ownership state in a nogc-enforced module ({provenance})
E1402
Owned value '{name}' is sealed into managed storage inside a nogc-enforced module ({provenance})
E1403
Heap value '{name}' crosses implicitly out of a nogc-enforced module ({provenance})
E1404
'{name}' is any-typed and could be heap-allocated in a nogc-enforced module ({provenance})
E1405
Closure capture of '{name}' escapes its scope in a nogc-enforced module ({provenance})
E1406
'{name}' has retaining or aliasing semantics not supported in a nogc-enforced module ({provenance})
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:
W2029
'@{decorator}' is not recommended in '{kind}' definitions -- use native property syntax
W2029 covers the Python property decorators -- @property, and the same-object
@x.getter / @x.setter / @x.deleter -- in favour of native property
syntax:
jac check --lint --fix rewrites the decorator form automatically
(property-to-native). As with W2006/W2007, a
Python-compat class is exempt. A cross-object @Base.x.setter extends a parent's
property and has no direct native form, so it is not reported.
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.
E2027
Endpoint clause ': Src --> Tgt' is only valid on an 'edge' archetype, not on {arch_type} '{name}'
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.
Emitted by jac check --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
W3050
strip-comments
Comment can be removed
opt-in
W3051
strip-docstrings
Docstring can be removed
opt-in
opt-in group: strip-comments and strip-docstrings are destructive "deslop" rules. They are never activated by select = ["all"] or ["default"]; they fire only when named explicitly in [check.lint]. See the config reference for details.
Argument '{name}' for server function '{func}' is given both positionally and by keyword
E5081
Unknown client framework '{framework}'
E5082
Client code imports '{name}' from '{module}', but '{name}' has no client-side presence
E5082 fires when a plain client import references a server symbol that does not bridge: server def:pub endpoints bridge automatically over RPC, so the fix is to make the symbol a def:pub endpoint, mark it (or its module) client, or move it into client code.
Emitted by CapabilityCheckPass when code uses JS-specific surface instead of Jac's common primitives, which work across all codespaces (Python, JS, native).
Code
Message
W6001
Use of JS-specific global '{name}' -- use '{alternative}' for cross-codespace portability
W6002
Use of JS-idiomatic method '.{method}()' -- use '{alternative}' for cross-codespace portability
W6003
Use of JS-specific keyword '{name}' -- use '{alternative}' for cross-codespace portability
W6004
Use of JS-specific property '.{prop}' -- use '{alternative}' for cross-codespace portability
Client call to server endpoint '{func}' passes function-typed parameter '{param}' -- functions cannot cross the RPC boundary
A def:pub function in a server-placed module is an HTTP endpoint whose arguments serialize over the wire, so a function-typed argument cannot cross it. Shared client-side logic should drop :pub so it is placed in the browser with its callers.