Decoding TypeScript Error Messages

Effect’s type system produces complex error messages. Here’s how to read them.

Common Error Catalog

Error MessageCauseSolution
Type 'X' is not assignable to 'Effect<...>'Missing yield* or wrong return type in a generatorAdd yield* before the effect, or return yield* for terminal effects
Context Service not found: myapp/ServiceMissing Effect.provide(Layer) for a required serviceProvide the layer: program.pipe(Effect.provide(MyService.layer))
Cannot yield a value of type 'X'The value is not a Yieldable typeUse explicit methods: Ref.get(ref), Deferred.await(d), Fiber.join(f) instead of yielding directly
Type 'Effect<A, E, R>' is not assignable to 'Effect<A, E, never>'The R channel still has unmet dependenciesProvide all required layers until R becomes never
Property 'catchAll' does not exist on type 'Effect'Using v3 API name in v4Rename to Effect.catch
Type 'Option<A>' is not assignable to 'Effect<A, ...>'Using v3 subtyping in v4 where Option is no longer an EffectUse .asEffect() or yield* in a generator
Property 'Default' does not exist on type 'typeof MyService'Using v3 Effect.Service auto-generated .Default layerDefine layers explicitly: static readonly layer = Layer.effect(this, this.make)
Expected 1 type arguments, but got 2 on Context.ServiceUsing v3 Context.Tag(id)<Self, Shape>() syntaxUse v4 syntax: Context.Service<Self, Shape>()(id)
Property 'Tag' does not exist on type 'typeof Context'Using v3 Context.Tag in v4Use Context.Service<Self, Shape>()(id)

”Type X is not assignable to Effect<…>”

// Error: Type 'number' is not assignable to 'Effect<number, never, never>'
Effect.gen(function*() {
  const result = 42 // forgot to wrap in an effect
  return result
})

// Fix: wrap values in Effect.succeed, or yield* the effect directly
Effect.gen(function*() {
  return yield* Effect.succeed(42)
})

This usually means you returned a plain value where an Effect was expected, or you forgot yield* before an effectful computation.

”Service not found” / “Context not provided”

// Runtime error: Context Service not found: myapp/Database
const program = Effect.gen(function*() {
  const db = yield* Database
  return yield* db.query("SELECT 1")
})

// Missing: Effect.provide(Database.layer)
Effect.runPromise(program) // crashes

// Fix
Effect.runPromise(program.pipe(Effect.provide(Database.layer)))

This is a runtime error, not a compile error. The service identifier in the message (e.g., myapp/Database) tells you which layer to provide.

Gotcha: Effect.runPromise accepts Effect<unknown, unknown, never>, so TypeScript won’t always catch missing layers at compile time. If your R channel is not never, you still have unmet dependencies.

”Cannot yield a value of type X”

// v4 error: Cannot yield a value of type 'Ref<number>'
Effect.gen(function*() {
  const ref = yield* Ref.make(0)
  const value = yield* ref // ref is not Yieldable in v4
})

// Fix: use explicit method
Effect.gen(function*() {
  const ref = yield* Ref.make(0)
  const value = yield* Ref.get(ref)
})

In v4, Ref, Deferred, and Fiber no longer implement Yieldable. They are plain runtime values. You must call their module methods explicitly.

Typev3 (yieldable)v4 (explicit)
Ref<A>yield* refyield* Ref.get(ref)
Deferred<A, E>yield* deferredyield* Deferred.await(deferred)
Fiber<A, E>yield* fiberyield* Fiber.join(fiber)

Type Mismatch on R Channel

// Error: Effect<User, DbError, Database> is not assignable to Effect<User, DbError, never>
const getUser = Effect.gen(function*() {
  const db = yield* Database
  return yield* db.query("SELECT * FROM users WHERE id = 1")
})

// R = Database, not never. You must provide it.
Effect.runPromise(getUser) // type error

// Fix
Effect.runPromise(getUser.pipe(Effect.provide(Database.layer)))

The R channel is Effect’s dependency tracker. R = never means all dependencies are satisfied. Any other R value means you need to provide more layers.

”Effect is not assignable to Effect” Variance Issues

// Error: Effect<A, E1, R> is not assignable to Effect<A, E2, R>
// where E1 is a broader union than E2

// Cause: you're returning an effect with more error types than declared
const fn = (n: number): Effect.Effect<number, ParseError> => {
  if (n < 0) {
    return yield* new ParseError({ input: String(n) }) // also returns RangeError in union
  }
  return Effect.succeed(n)
}

// Fix: include all possible error types in the signature
const fn = (n: number): Effect.Effect<number, ParseError | RangeError> => {
  // ...
}

Effect’s E channel is contravariant in some contexts. If your function can produce multiple error types, all of them must appear in the type signature.

v3 to v4 Migration Type Errors

v3 Codev4 ErrorFix
import { Either } from "effect"Module not foundimport { Result } from "effect"
Context.Tag("X")<X, Shape>()Wrong type argument countContext.Service<X, Shape>()("X")
Effect.Service<X>()("X", { effect })Property doesn’t existContext.Service<X>()("X", { make }) + explicit Layer.effect
Effect.catchAll(...)Property doesn’t existEffect.catch(...)
effect/TMapModule not foundeffect/TxHashMap
effect/TestClockModule not foundeffect/testing/TestClock
@effect/platform/HttpClientPackage not foundeffect/unstable/http/HttpClient

See v3 to v4 Migration for the full import map.