Hem reports 121 diagnostic codes. Each one is registered once, with the title and
explanation below, and reaches you through three surfaces: rendered CLI output, editor
diagnostics through the language server, and hem explain <code>.
This page is generated from the compiler’s diagnostic registry, so it always matches the codes the installed compiler can actually report.
Syntax
Lexer and parser diagnostics. These report before any type information exists.
HEM1001
unterminated string literal
Hem string literals open and close with " on a single line. If you need a line break inside a string, use a template literal with backticks instead.
HEM1002
unterminated block comment
Block comments open with /* and close with */. The lexer reached the end of the file while still inside this comment.
HEM1003
unexpected character
This byte is not part of any Hem token. It usually means a typo, a paste from a different language, or a Unicode look-alike character.
HEM1004
expected an expression
Something that produces a value must appear here: a literal, a name, a call, a match, an if/else, or a parenthesized expression.
HEM1005
expected a binding name
Bindings introduce a name before the rest of the construct continues: let total = price * count, use handle = open(), or for item in items { ... }. A binder is an identifier or a destructuring pattern; a parameter may also carry an optional marker (x?: T) or be a rest element (...xs: T[]). Reserved keywords such as from cannot be binding names or field names in record binding patterns, even when the field is aliased. Choose a non-reserved binding name and read reserved properties separately: let sourceId = record.from. The contextual keywords type and error can be ordinary binding names.
HEM1006
expected = after the binding name
Every binding takes an initializer: let name = expression or use handle = expression. Hem has no uninitialized bindings.
HEM1007
expected a statement
Statements begin with a keyword like let, use, type, error, return, or an expression. This token cannot begin a statement.
HEM1008
unterminated template literal
Template literals open and close with backticks. A ${ ... } hole contains a full Hem expression, and nested template literals must close before the outer template can continue.
HEM1009
unterminated regex literal
A regex literal starts with / only in expression-operand position. Character classes and escapes are part of the regex body, but the literal must close before the end of the line.
HEM1010
unclosed delimiter
Delimited syntax must close the delimiter it opened. The parser keeps the recovered region in the tree so formatting and diagnostics can continue after the missing delimiter.
HEM1011
unparenthesized unary operand before **
Hem follows JavaScript’s exponentiation rule: -a ** b is rejected because the unary expression must be parenthesized as (-a) ** b.
HEM1012
?? mixed with && or ||
Hem keeps JavaScript’s nullish-coalescing restriction. Parenthesize the logical expression or the coalescing expression to make the grouping explicit.
HEM1013
ill-delimited TypeScript type extent
Type syntax is extent-scanned in @hem-lang/syntax and parsed later by TypeScript. When brackets or delimiters do not balance, Hem clamps the raw type extent at a safe boundary and continues parsing.
HEM1014
assignment in expression position
Hem intentionally keeps assignment out of the expression precedence table. Write target = expression as its own statement, or bind a new value with let name = expression.
HEM1015
retired: generic arrow type parameters were deferred
Retired in M0.11. Generic arrows now parse when the type parameter list uses the TSX-compatible <T,> spelling or an extends bound; <T>(x) => x is JSX and reports the A.8 teaching diagnostic instead.
HEM1016
expected in in for loop
A for loop names one binder and then the iterable expression: for item in items { ... }. The in keyword separates the binder from the loop source.
HEM1017
expected loop body
Loops run a block. Write for item in items { ... } or while condition { ... } with the { ... } body on the loop statement.
HEM1018
missing binding initializer
Every let or use binding has the shape name = expression. Hem has no uninitialized bindings, so the expression must appear after =.
HEM1019
and without binding group
The and keyword is a statement-level separator inside binding groups: let a = one and b = two. Start the group with let or use before adding and members.
HEM1020
missing same-line operand
raise and throw take a same-line operand: raise problem or throw error. A value on the next line starts a new statement, so it is not the operand.
HEM1021
expected => after pattern
Match and catch arms separate the pattern from the arm body with =>: | Ok(value) => value. The pattern stays to the left of the arrow, and the expression or block to run stays to the right.
HEM1022
expected an arm body
An arm body is either an expression or a { ... } block. Write | pattern => expression for a value arm, or | pattern => { statements } when the arm needs statements.
HEM1023
catch guards are deferred
Catch arms currently dispatch only on the error pattern. To branch by an extra condition, catch the wider pattern, use match inside the arm, and raise the original error in the fallback arm: | err => match err { | Specific => handle() | _ => raise err }.
HEM1024
expected variant member
A variant member starts with a name and may carry one parenthesized payload: type Result = | Ok(T) | Err({ message: string }).
HEM1025
unclosed match body
A match expression opens its arm list with { and closes it with }. Each arm stays inside that body: match value { | pattern => result }.
HEM1026
unclosed class body
Hem keeps class bodies as raw interop regions in this milestone, but the outer { ... } still has to balance so the parser knows where the class declaration ends.
HEM1027
unclosed service body
A service declaration opens its member list with { and closes it with }. Service members stay one per line inside that body: service Api { get: Request => Response }.
HEM1028
malformed import form
Imports use the JavaScript module shapes: import "side-effect", import name from "module", import { name as alias } from "module", or import * as ns from "module". import type, import defer, import source, and trailing with { ... } attributes use the same module-source position.
HEM1029
mismatched JSX closing tag
A JSX element must close with the same tag name it opened: <Card>...</Card>. Member tags compare by their full dotted name, so <Foo.Bar> closes with </Foo.Bar>.
HEM1030
unclosed JSX element
A non-self-closing JSX element must eventually close. Use </Tag> for elements, </> for fragments, or write the opening tag as self-closing with />.
HEM1031
unbraced JSX attribute value needs delimiters
Unbraced JSX attribute values admit literals and postfix chains only. JSX’s > and / are tag closers, so binary and unary operators would be ambiguous: write n={a + b} or n=(a + b) instead of n=a+b.
HEM1032
generic arrow needs a trailing comma
In expression position, < starts JSX. Hem follows TSX: a generic arrow must disambiguate its type parameters with a trailing comma, as in <T,>(x: T) => x, or with an extends bound.
HEM1033
expected JSX attribute or tag end
Inside a JSX opening tag, write an attribute name, name?, name=value, a spread {...value}, >, or />. A bare name is a pun that passes the in-scope binding; write name={true} for a literal boolean true.
HEM1034
block after let–else
let–else is not an if/else. Its else runs one diverging statement — return, throw, raise, break, or continue — directly, with no surrounding { }. Write else return 0; a block here would be read as an object literal, which cannot diverge.
HEM1035
increment and decrement are removed
Hem removes ++ and -- in both their prefix and postfix forms: their value-versus-effect duality hides a mutation inside an expression. Increment a let mut binding with a compound assignment statement — x += 1 or x -= 1 — on its own line. A space keeps the unary operators apart, so a + +b still parses as addition of a unary plus.
HEM1036
const binding is removed
Hem’s let is TypeScript’s const: it declares a binding that cannot be reassigned. Write let name = value, including for destructuring and exported bindings. Use let mut when the binding needs reassignment; it compiles to TypeScript’s let.
HEM1037
var binding is removed
Hem bindings are block-scoped. Replace var with let mut to allow reassignment, or use let when the binding is never reassigned. The quick fix uses let mut; it does not preserve JavaScript’s function-scoped hoisting.
Language
Hem’s own semantic rules: absence, matching, bindings, operators, and declarations.
HEM2001
boundary any demoted
Hem does not let any silently disable checking. A value whose inferred TypeScript type contains any is emitted with an as unknown boundary cast. Narrow it with a predicate, schema parser, or explicit safe cast before using it.
HEM2002
boolean value required
Hem conditions and logical operators accept only booleans, so JavaScript truthiness cannot leak 0, an empty string, or another accidental falsy value into control flow. Write an explicit comparison such as items.length > 0, value != None, or ready == true.
HEM2003
double optional type
Hem’s ?T expands to T | null | undefined, an unboxed nullable. Applying the ? prefix twice would produce the same union, so a literal ??T is rejected rather than silently collapsed. Instantiating a generic ?T with an already-optional argument does collapse silently; only spelling the double prefix by hand is an error. Write ?T for a single optional, or Option<T> when you need a boxed optional that can itself be absent.
HEM2004
bind outside effect block
Postfix ! is Effect’s bind operator, not TypeScript’s non-null assertion. An optional read needs absence handling: capture the read and check it, provide a fallback, or establish a stronger input contract. Preserve when and how often the read executes. For a Promise, await it in an async context; awaiting does not itself establish that the resolved value is present. For Effect operations in collection callbacks, compose them with Effect.forEach and bind the resulting Effect in the enclosing effect block. This diagnostic is reported before operand types are checked, so its guidance is conditional and has no automatic rewrite.
HEM2005
pattern usefulness
A match with missing cases or an open constructor set can fall through without a value, so HEM2005 refuses it; tuple scrutinees name missing combinations in universe order, capped at three plus a count. For a closed constructor set, add explicit arms so future cases require another decision; an intentional catch-all remains legal but also handles new cases without another missing-case diagnostic. An open constructor set requires a fallback for values outside the known cases, and guarded arms never establish exhaustiveness because their guards may reject every value. A redundant arm is a warning because it is dead but does not change the result. An unknown constructor names a case the matched type does not have, usually a misspelling; correct the name rather than widening the match.
HEM2007
group member references a sibling binding
An and group is simultaneous: every initializer starts before any of the group’s names are bound. Hem does not infer a dependency graph because data dependency does not define effect order — a rate limiter, for example, must stay explicit — and an edit must not silently serialize a formerly concurrent group. Write the dependency as a separate binding first, then start the independent group: let shared = make(); let a = consume(shared) and b = other().
HEM2008
inconsistent binding group
Binding groups use one execution shape. Plain groups evaluate left to right, await groups start promises together, and effect-world ! groups arrive with the M4a extension. Core use is not grouped because a partially failed concurrent acquisition can leak without scope semantics; write separate use statements until extension-world scoped groups are available.
HEM2009
nested bind inside a group member
await groups are for flat concurrent starts: let a = await fa() and b = await fb(). A nested await or postfix ! inside an argument creates a waterfall before that member can enter Promise.all. Bind the inner result first, then use it from a later binding or group member.
HEM2010
forbidden surface type
Hem keeps any out of source type positions. Use unknown for unchecked values and narrow before use. Exact T | null and T | undefined types are writable and pass through to TypeScript; ?T expands to T | null | undefined and therefore admits both absence values. Writing a nullish type does not permit a null or undefined value literal or an unchecked assertion.
HEM2011
catch tag is not an error class
Core named catch arms dispatch with instanceof, so each named tag must resolve to a class derived from Error. Effect catch arms must name a tag in the checked error channel. If TypeScript exposes any for the caught expression, give it a known type so Hem can check the arm. For core catches, use a declared Hem error, import an Error subclass, or write a binding arm such as | cause => handle(cause) for an untyped thrown value.
HEM2012
use value is not a resource
Core use registers cleanup at block exit and therefore requires Disposable or AsyncDisposable evidence from TypeScript. Ordinary values belong in let; resources without the protocol can be wrapped with a library adapter or DisposableStack.
HEM2013
assignment needs a mut binding
Hem bindings are immutable unless their declaration includes mut. Prefer shadowing with a new let when computing a new value; use let mut name = initial only when the algorithm genuinely needs in-place assignment.
HEM2014
let-else branch must diverge
A refutable let only makes its bindings available after the pattern succeeds. Its else branch must leave the current control-flow path, so write return, throw, raise, break, or continue instead of a value-producing expression.
HEM2015
component name is already claimed
Exported top-level PascalCase arrow bindings that produce JSX keep their authored emitted name so React Fast Refresh can identify them. Two such components cannot share one name; rename one component instead of relying on Hem’s ordinary shadow suffixes.
HEM2016
pattern bindings must be unambiguous
A successful pattern introduces each name exactly once. In an or-pattern, every alternative must introduce the same names so the arm or binding has one stable scope regardless of which alternative matched. Rename duplicate bindings or make the alternatives bind the same set of names.
HEM2017
variant payload has multiple positionals
A variant constructor carries either a single positional payload (bound to value) or a record whose fields spread onto the discriminated union. Several positional fields have no field names to spread and no stable accessor, so they are rejected permanently rather than deferred. Rewrite the payload as a record: Rect({ w: number, h: number }).
HEM2018
unused expression result
Hem refuses effect-free expression statements and unused calls or await results whose checked type is Effect, Promise/PromiseLike, canonical Option/Result from @hem-lang/std, or the configured transport’s boxed Option/Result. Await or return a Promise or handle its rejection; compose or return an Effect or run it at a runtime boundary, using postfix expression! inside an effect block. Handle Option/Result cases with match, or use postfix ! in an effect block to propagate absence or failure; prefix ! is boolean negation. Ordinary side-effecting calls (array.push, map.set, console.log) and ?T results remain legal. let _ = expression deliberately evaluates and discards the result without running an Effect, handling a Promise rejection, or inspecting carrier cases; let _ = expression! runs an Effect here and discards its success value.
HEM2019
tuple-scrutinee arm shape
match [a, b] is multi-scrutinee syntax: the bracketed elements evaluate to independent values and each arm is a fixed-length array pattern with one column per scrutinee. No runtime tuple is materialized, so a rest element, an as over the whole array pattern, or a length mismatch has no meaning. Write one […] pattern per arm, using per-column or-patterns ([A | B, C]) for alternatives and per-column as for bindings.
HEM2020
brand declarations cannot be generic
A brand declaration mints exactly one identity constructor for one fixed base type. Hem does not support a generic brand family parameterized by <T> in v1. Write a concrete, non-generic brand for each base type you need, or drop brand and declare an ordinary generic type alias instead.
HEM2021
non-numeric + operand
Hem’s + is arithmetic only: both operands must check as number, or both as bigint — never a mix, and never a string. String concatenation has exactly one spelling, a template literal, so a stray numeric value can never silently paste itself into a string and a string can never silently become NaN in an arithmetic expression. += follows the same rule as +. Unary + narrows further and requires an already-number operand, since it is a coercion in disguise; spell the coercion explicitly with Number(x) instead. Building a string across a loop can use a parts array joined with .join("") rather than repeated +=.
HEM2022
while-let needs a refutable pattern
while let re-tests a refutable pattern each iteration and ends the loop when it fails, the way let–else ends the path by diverging. A pattern that always succeeds — a bare binding, _, or a record/array of only bindings — never fails, so the loop would spin forever. Bind the value with an ordinary let inside a while <condition> loop, or match on a refutable shape like Some(value).
HEM2023
deriving Eq target not derivable
deriving Eq recurses into a field only when its type is something the compiler can already compare structurally: a primitive, an array, ?T, a brand, or another Hem type that itself deriving Eqs. A field typed as a Hem variant or error without deriving Eq is refused rather than silently compared by reference, because the compiler already knows its shape and a silent reference comparison there would hide a real difference. A genuinely foreign type — an imported class, Date, RegExp — has no such comparator to call, so it compares by reference without a diagnostic; that is deriving Eq’s documented, structural-only boundary, not an oversight. Add deriving Eq to the named type, or don’t derive on the type holding it. Only Eq is a recognized derivation in this version; any other deriving name is refused until that derivation ships.
HEM2024
framework directive is outside the module prologue
Hem preserves top-level JavaScript directive prologues byte-for-semantics in emitted TypeScript. React’s use client and use server directives only define a module boundary when they precede every import, declaration, and executable statement; writing one later would emit an inert string expression, so Hem diagnoses the placement instead of silently changing framework behavior.
HEM2025
ambiguous carrier constructor
Capitalized Some, None, Ok, and Err are contextual vocabulary shared by nullish values, canonical carriers from @hem-lang/std, and configured Effect carriers. Bare None infers undefined; other constructors need a checked expected carrier rather than guessing their runtime shape. Contextual Some, Ok, and Err each take exactly one positional argument, giving each constructor one unambiguous payload. Add an annotation when contextual syntax is useful, or use the canonical qualified constructor explicitly. Nullish Some(value) emits the value unchanged, so a nullish payload remains absent; choose boxed Option<Option<T>> when nested absence must stay distinct.
HEM2026
unsound carrier binding
Carrier binding is checked control flow. Hem propagates the original None or Err only from a native ?T or a canonical carrier from @hem-lang/std, and only when that residual fits the nearest propagation boundary of the same representation: an arrow return or an effect block’s success channel. Foreign lookalikes, implicit cross-carrier conversion, and nested refutable payloads require an explicit else or match.
HEM2027
nullish Effect lift without policy
Postfix bang can adapt canonical Result and Option carriers from @hem-lang/std because Err carries an error and the configured Effect transport defines Option’s missing-element error. Native ?T carries neither. Hem refuses to invent application policy; use an explicit pattern and raise the domain error you intend.
HEM2028
unchecked type assertion
Hem assertions may widen an already checked value, but cannot manufacture a narrower type. Imported declarations remain trusted boundaries; unchecked assumptions require a reviewed TypeScript shim.
HEM2029
unchecked predicate signature
Imported validators remain trusted contracts. Hem does not verify an explicitly authored is or asserts signature against its implementation; use checked narrowing and result values instead.
HEM2030
unsafe writable alias
Readonly access cannot silently become writable access. A mutable alias must preserve the source value’s read and write contract; a shallow copy does not isolate nested values.
HEM2031
invalidated property refinement
A readonly view does not prove that another alias cannot mutate the object. Capturing an object reference does not preserve its property refinements. Moving a read earlier can change behavior, so this diagnostic provides no automatic edit.
HEM2032
type-view expression used as a write target
A checked widening assertion or conformance check describes a value, not permission to replace its storage. Using it as a write target can bypass constant bindings, readonly properties, and the original location’s accepted type.
HEM2033
unsafe tuple mutation
A tuple’s required positions and slot types must survive writes through every supported authored alias. Destructive methods and writes that cannot preserve that contract are refused; readonly views do not copy the tuple. Compatible element replacement and rest appends remain available.
HEM2034
raise of a bare error constructor
Raising a class does not construct an error: core catch arms and Effect catchTags expect instances. Hem inserts new Name() for raise Name only when Name is an unshadowed, locally declared error with no fields. Local errors with fields use raise Name({ … }), which inserts new. Other constructor-only values, including imported error classes and class-valued properties, require explicit raise new Name(…) in both worlds.
Project and tooling
Configuration, emit targets, and constructs the compiler does not yet lower.
HEM3001
Effect extension is incompatible
The Effect extension probes every runtime and type capability its generated code relies on before lowering starts. Upgrade the configured package to the supported Effect 4 cohort or point effectImportSource at one that exports the complete contract; Hem reports the mismatch once instead of exposing a cascade from generated TypeScript.
HEM3002
emit target collides with a handwritten file
Sibling emit writes foo.ts next to foo.hem (ADR 0005). A file without the generated-from banner is treated as handwritten and never overwritten; rename one of the two files.
HEM3003
construct is not emittable yet
Rather than guess at a lowering, the compiler refuses the whole file when it meets a construct it does not yet emit. The message names the construct and, where available, a supported alternative. Awaited binding groups require annotations on every member or none; annotating every member retains concurrent evaluation. Range loops bind a single number; destructure ordinary iterable values instead. An intentional wildcard discard uses unmodified let _ = value; use a named binding for annotations, mutation, or recovery. Constructs rejected on principle carry their own permanent diagnostic instead of this one.
HEM3004
TypeScript project is not ready
Hem uses the real TypeScript project for module resolution, libraries, JSX, and supporting files. It overlays its required strictness only inside Hem’s private no-emit checker, so the application build need not adopt those options at once. Add or repair the reported project configuration, then run hem check again.
HEM3005
formatter output diverged
The formatter reparses its own output and compares it to the input before returning it. When the two parse trees differ — a dropped comment, an unbalanced delimiter, a reordered token — it refuses the edit and hands back the original bytes so a formatter defect can never silently corrupt a program. Please report the input that triggered this.
HEM3006
incompatible standard carrier package
Hem grants contextual constructors, must-use behavior, carrier binding, and Effect adapters only to the canonical Option and Result carriers from @hem-lang/std. Those features depend on the standard carrier shapes and operations matching this Hem release. Align the Hem and @hem-lang/std versions rather than patching structural lookalikes.
HEM3007
construct is not emittable by design
This construct is refused on principle rather than pending support, so reworking the code is the only path forward — the message names the rule that rules it out. Constructs that merely await a lowering report HEM3003 instead.
HEM3008
generated sibling was edited
Generated siblings carry a hash of their body in the banner. Build, watch, and Vite refuse to overwrite or remove a sibling whose body no longer matches; hem check reports the same error without writing. Move the change into the .hem source, then run hem build --overwrite-edited or delete the sibling and rebuild. The flag discards edits to generated siblings, including stale siblings, and reports each overwrite or removal. It is only available for one-shot builds, cannot be combined with –watch, and never overrides handwritten-file collisions (HEM3002). Watch and Vite rebuild when a known sibling is deleted or a refused sibling changes. CRLF and LF line endings are equivalent. Older banners without a hash remain overwritable and gain a hash on the next build.
Effect
Safety rules for the optional Effect extension. None of these can report unless hem.effectImportSource is configured.
HEM4102
Effect requirements are not provided
Every ! records the Effect requirement channel at its authored site. Supply the listed services with Effect.provide or a Layer before calling a runner; the related locations show exactly where each requirement entered the program.
HEM4103
effect bind crosses a function boundary
A generator yield belongs to the nearest effect or resource block. A callback creates another function, so a ! inside it cannot yield from the surrounding block. For collections, use Effect.forEach(items, (item) => work(item), { concurrency: 5 })!; for one callback, return an Effect and bind it outside the callback.
HEM4105
scope-bearing Effect must use use
A plain postfix ! can let a scope-bearing acquisition escape without making ownership visible. Bind it with use inside an effect or resource block: let lease = acquire()! becomes use lease = acquire(). effect owns and closes the scope, while resource passes Scope to its caller.
HEM4106
nested effect runner
Calling an Effect runner inside an effect block starts a separate execution boundary. That child loses the surrounding services, supervision, test clock, interruption scope, and tracing context. Compose the child Effect with postfix !; at a genuine application edge, keep the runner outside the effect block. An explicitly captured Runtime is the visible escape hatch when a separate run is deliberate.
HEM4107
multiple effect provide boundaries
Repeated Effect.provide on one Effect can build and close related Layers in separate lifecycles, duplicating acquisition or breaking sharing. Compose dependencies with Layer.provide and combine independent outputs with Layer.merge, then use one application-edge Effect.provide.
HEM4108
dependent layers in Layer.mergeAll
Layer.mergeAll is for independent Layers. When one Layer requires a service another Layer builds, merging them as peers does not preserve dependency order or sharing. First pipe the dependent Layer through Layer.provide(provider), then merge that closed composition with genuinely independent Layers.
HEM4109
leaked service requirements
A service method should expose the capability promised by its service declaration, not the dependencies used to implement its live Layer. Bind implementation services while constructing the Layer so returned methods are closed over them. If a dependency is genuinely request-local and caller-provided, include it explicitly in the method’s Effect requirement channel.
HEM4110
unsafe public effect channel
An exported Effect promises callers a typed failure channel and a complete service requirement set. any or unknown in either channel makes that promise unverifiable. Validate an imported untyped value once and assert it from unknown to a concrete Effect type at the import boundary; do not weaken every downstream declaration.
HEM4111
narrowed effect carrier channel
Type assertions must not claim an Effect has fewer possible successes, failures, or service requirements than its checked value. Such a cast can hide an unhandled failure or missing service without changing runtime behavior. An imported unknown may be asserted once to a concrete Effect contract as an explicit boundary; assertions between two recognized Effect types may widen channels but never narrow them.
HEM4112
defer outside effect scope
A deferred cleanup must belong to a visible Effect Scope. Put it inside effect {} when the block should own and close that scope, or inside resource {} when the caller should provide Scope. Ordinary synchronous blocks have no Effect lifetime to attach the finalizer to.
HEM4113
defer cleanup type mismatch
Effect.addFinalizer cannot report a typed cleanup failure after the surrounding scope has already chosen its result. Hem therefore accepts only an existing Effect<void, never, R>: synchronous work must be lifted explicitly with Effect.sync, returned values must be discarded explicitly, and typed failures must be handled before defer. Exit-sensitive cleanup remains an explicit Effect.addFinalizer((exit) => ...) call.
HEM4114
unstable traced operation binding
Hem derives the trace name from the project-relative module path, enclosing named bindings, and operation name. Local bindings may capture dependencies. Colliding names receive a source-location suffix. Mutable, destructured, grouped, wildcard, and anonymous definitions are not supported. Bind the operation with let operation = effect traced (...) => { ... } in the appropriate scope.
HEM4115
promise hidden in effect success
An Effect must own asynchronous execution to supervise, interrupt, time out, retry, and classify its failures. Effect.succeed(promise) and Effect.sync(() => promise) instead succeed immediately with the Promise as an ordinary value. Use Hem await in an effect block or construct the operation with Effect.tryPromise.
HEM4116
duplicate Effect package identities
Effect values, Context tags, Scope, Layers, fibers, and Hem’s declaration-origin checks all depend on one coherent runtime identity. Two physical installations remain distinct even when their versions are equal. The diagnostic names a representative incoming import/reexport for each root, or a participating declaration when no such edge is available. Follow those paths to the importing package and repair its dependency graph with the project’s package manager and existing lockfile. Keep native TypeScript tests and consumers in the project, then rerun the full check/build/test gate. Do not suppress this check or remove imports merely to hide a second installation.
HEM4117
generic Effect service has no runtime identity
TypeScript can distinguish Cache<User> from Cache<Order>, but a generic Context tag cannot: its type arguments do not exist at runtime. Use concrete tags such as UserCache and OrderCache, or construct tags from explicit runtime keys. Generic methods on a nongeneric service are safe because they do not create competing service identities.
HEM4118
Effect nested without execution
An Effect placed in another Effect’s success or failure channel is ordinary data: the runtime does not execute, supervise, retry, or interrupt it. Hem diagnoses nested carriers at constructors and generator returns. Use postfix ! to execute the inner Effect, or model an intentional Effect-valued result at an explicit boundary rather than accidentally returning it from an operation.
HEM4119
for await inside an Effect block
Inside an effect {} or resource {} block, await lifts a single Promise through Effect.tryPromise; it does not perform native async iteration. Use Stream.fromAsyncIterable with Stream.runForEach to iterate a Stream, use Effect.forEach over an array, or move the loop into an async helper arrow defined outside the block and lift the helper’s Promise with await.
Translated TypeScript diagnostics
TypeScript’s own codes, re-rendered in Hem’s vocabulary and remapped to authored Hem source. The code is TypeScript’s so it stays searchable, but the wording and the reported position are Hem’s.
TS18046
value has unknown type
An unknown value is safe to receive but cannot be used until its shape is proven. Narrow it with a type guard, pattern, or checked conversion before accessing members or calling it.
TS18047
value may be null
A nullable value may be absent. Match or otherwise handle None before using the present value.
TS18048
value may be undefined
An undefined value may be absent. Match or otherwise handle None before using the present value.
TS2304
binding not found
A name must be declared in the current scope or imported from another module before it can be used. JSX punning passes the binding with the same name; write required={true} when the intended value is a literal boolean. type and error are contextual keywords: at the start of a statement type Name = ... declares a type alias and error Name(...) declares an error, but everywhere else they are ordinary names — an unbound one here is usually a declaration that lost its name, or a raise you meant to write. Otherwise add a declaration such as let value = expression, import the missing binding, or correct the spelling.
TS2305
module member not exported
Named imports must match a public export from the target module. Check the module’s export list, then change either the export or the name inside import { name } from "module".
TS2307
module not found
The project must be able to resolve every imported module through its file paths, installed packages, and tsconfig.json module-resolution settings. Correct the specifier or make the dependency available to the project.
TS2322
type mismatch
The value and its destination have different types. Hem shows the smallest incompatible field when TypeScript provides that structure; change the value or the destination annotation so the two types agree.
TS2339
property not found
Property access must name a member available on the value’s current type. Correct the name, narrow a union before accessing variant-specific data, or add the property to the type that owns it.
TS2345
argument type mismatch
A call argument must be assignable to the corresponding parameter. Change the argument value or choose a function whose parameter accepts that type.
TS2349
value is not callable
Only values with a call signature can use value(...). Pass a function, select a callable member, or remove the call parentheses.
TS2351
value is not constructable
The new operator requires a value with a construct signature. Use a class or constructor value, or call a factory function without new.
TS2352
cast types do not overlap
Convert the value to the required representation, or narrow it with a checked condition before using it. For example, use String(value) to convert a number to text. Hem does not support unchecked assertions: routing a value through unknown does not establish its type. Do not move the assertion into TypeScript merely to bypass this refusal; a new unchecked boundary requires explicit human review.
TS2353
unknown object field
An object literal may provide only fields declared by its expected type. Remove the extra field, correct its name, or extend the destination type when the field belongs there.
TS2365
operator type mismatch
Binary operators accept specific operand types. Convert one side so both operands fit the operator, or choose an operation defined for the two values you have.
TS2367
comparison has no overlap
Two types with no possible shared value can never compare equal. Correct the compared value or narrow the surrounding branch so both sides can describe the same value.
TS2454
binding used before assignment
Every read must follow an assignment on all control-flow paths. Move the read later or ensure each branch assigns the binding before control can reach it.
TS2540
readonly field write
let mut permits rebinding, not field mutation. Create an updated record instead of writing through a readonly reference. If mutation is intended, declare the field mut in a record type you own and review its callers; a readonly reference does not grant write permission. These choices can change identity or mutation policy, so Hem offers no automatic fix.
TS2551
property name misspelled
The value has a property with a nearby spelling. Use the suggested property if it is intended; otherwise narrow or change the value’s type before accessing a different member.
TS2552
binding name misspelled
A nearby in-scope binding has a similar spelling. Use the suggested name if it is the intended value; otherwise import or declare the missing binding explicitly. type and error are contextual keywords rather than values here, so an unbound one is usually a declaration that lost its name or a raise you meant to write; the suggested built-in may also be what you wanted.
TS2554
wrong argument count
Calls must provide an argument count accepted by the selected signature. Add the missing arguments, remove extras, or call a signature with matching optional and rest parameters.
TS2561
object field misspelled
An object literal contains a field whose spelling is close to a declared field. Rename it to the suggestion when appropriate, or update the expected type to declare the intended field.
TS2722
optional function called
An optional function cannot be called until its absence case is handled. Match Some(fn) before calling fn(...), or provide a non-optional fallback function.
TS2741
required field missing
Every required field in the destination type must be present. Add the named field with a compatible value, or make the field optional in the owning type when absence is valid.
TS2769
no overload matches
An overloaded function publishes several accepted call shapes, and this call matches none of them. Compare the arguments with each signature and change the count or types to fit one complete overload.
TS7006
parameter type is implicit
Strict projects do not allow an untyped parameter to become any. Add a parameter annotation such as (value: string) => ..., or supply a contextual function type that determines it.
TS7053
key cannot index type
Indexed access needs a key known to the target type or an index signature that accepts it. Narrow the key to keyof Target, use a declared property, or model the dynamic key space explicitly.