Skip to content

Diagnostics

Every diagnostic code Hem can report, with its title and explanation.

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.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close