Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Effect-TS/tsgo/llms.txt

Use this file to discover all available pages before exploring further.

Correctness diagnostics flag code that is structurally invalid or likely to cause runtime bugs. Most are errors by default and block compilation when an Effect type is misused.
Rules marked ❌ are errors by default. Rules marked ⚠️ are warnings. Rules marked ➖ are off by default and must be enabled in diagnosticSeverity.

anyUnknownInErrorContext

Severity: ➖ off by default  ·  V3/V4: ✓ / ✓ Detects any or unknown types in the error (E) or requirements (R) channels of an Effect. These imprecise types defeat the purpose of Effect’s typed error and dependency channels. Enable this rule to enforce fully typed channels across your codebase.
// ❌ Violation — error channel is `unknown`
declare const myEffect: Effect.Effect<number, unknown, never>

// ✅ Correct — use a concrete error type
declare const myEffect: Effect.Effect<number, DatabaseError, never>
To enable:
{ "diagnosticSeverity": { "anyUnknownInErrorContext": "warning" } }

classSelfMismatch

Severity: ❌ error  ·  Fix: 🔧  ·  V3/V4: ✓ / ✓ Ensures that the Self type parameter passed to Effect.Service, Effect.Tag, ServiceMap.Service, or Schema class constructors matches the class name. A mismatch breaks the service identity used internally by the Context system.
import { Effect } from "effect"

// ❌ Violation — Self parameter says "WrongName"
class Database extends Effect.Service<WrongName>()("Database", {
  effect: Effect.succeed({ query: () => Effect.void })
}) {}

// ✅ Correct — Self parameter matches the class name
class Database extends Effect.Service<Database>()("Database", {
  effect: Effect.succeed({ query: () => Effect.void })
}) {}
The quick fix updates the type argument to match the class name automatically.

duplicatePackage

Severity: ⚠️ warning  ·  V3/V4: ✓ / ✓ Warns when multiple versions of an Effect-related package are present in the program’s dependency graph. Duplicate packages cause services to have different identities in each copy, breaking Context lookups silently.
⚠️ Multiple versions of package 'effect' detected: 2.x.x, 3.x.x.
Consider cleaning up your lockfile, or add 'effect' to allowedDuplicatedPackages to suppress this warning.
If a duplicate is intentional (for example during a migration), add the package to allowedDuplicatedPackages:
{ "allowedDuplicatedPackages": ["effect"] }

effectFnImplicitAny

Severity: ❌ error  ·  V3/V4: ✓ / ✓ Mirrors TypeScript’s noImplicitAny check for parameters inside Effect.fn, Effect.fnUntraced, and Effect.fnUntracedEager callbacks when no outer contextual function type provides the annotation. Requires noImplicitAny: true in tsconfig.json.
import { Effect } from "effect"

// ❌ Violation — `id` has implicit any type
const getUser = Effect.fn("getUser")(function* (id) {
  return yield* fetchUser(id)
})

// ✅ Correct — explicit type annotation
const getUser = Effect.fn("getUser")(function* (id: string) {
  return yield* fetchUser(id)
})

floatingEffect

Severity: ❌ error  ·  V3/V4: ✓ / ✓ Detects Effect values that are created as standalone expression statements — neither yielded inside a generator nor assigned to a variable. A floating Effect is never executed and indicates a missing yield* or assignment.
import { Effect } from "effect"

// ❌ Violation — the effect is discarded
Effect.gen(function* () {
  Effect.log("hello") // floating: never executed
})

// ✅ Correct — yield* the effect to execute it
Effect.gen(function* () {
  yield* Effect.log("hello")
})

genericEffectServices

Severity: ⚠️ warning  ·  V3/V4: ✓ / ✓ Prevents defining Effect.Service or Effect.Tag classes with type parameters. Generic services cannot be discriminated at runtime because different instantiations share the same tag identifier, leading to unexpected behavior when looking up services from Context.
import { Effect } from "effect"

// ❌ Violation — generic type parameter makes runtime discrimination impossible
class Repository<T> extends Effect.Service<Repository<T>>()("Repository", {
  effect: Effect.succeed({ findById: (id: string) => Effect.succeed({} as T) })
}) {}

// ✅ Correct — concrete service type
class UserRepository extends Effect.Service<UserRepository>()("UserRepository", {
  effect: Effect.succeed({ findById: (id: string) => Effect.succeed({} as User) })
}) {}

missingEffectContext

Severity: ❌ error  ·  V3/V4: ✓ / ✓ Detects Effect values whose requirements channel (R) contains services that have not been provided. This is analogous to a missing import — the effect cannot run without those services.
import { Effect } from "effect"

class Database extends Effect.Service<Database>()("Database", {
  effect: Effect.succeed({ query: () => Effect.void })
}) {}

// ❌ Violation — Database is required but not provided
const program: Effect.Effect<void, never, never> = Effect.gen(function* () {
  const db = yield* Database
  yield* db.query()
})

// ✅ Correct — provide the Database layer
const program = Effect.gen(function* () {
  const db = yield* Database
  yield* db.query()
}).pipe(Effect.provide(Database.Default))

missingEffectError

Severity: ❌ error  ·  Fix: 🔧  ·  V3/V4: ✓ / ✓ Detects Effect values whose error channel (E) contains error types that are not handled by the type expected at that position. This flags type-level mismatches where errors leak through unhandled.
import { Effect, Data } from "effect"

class NotFoundError extends Data.TaggedError("NotFoundError")<{}> {}
class ValidationError extends Data.TaggedError("ValidationError")<{}> {}

declare function findUser(): Effect.Effect<User, NotFoundError | ValidationError>

// ❌ Violation — ValidationError is unhandled
const result: Effect.Effect<User, NotFoundError> = findUser()

// ✅ Correct — handle or propagate all error types
const result: Effect.Effect<User, NotFoundError> = findUser().pipe(
  Effect.catchTag("ValidationError", () => Effect.fail(new NotFoundError()))
)
The quick fix adds the missing error types to the expected type.

missingLayerContext

Severity: ❌ error  ·  V3/V4: ✓ / ✓ Detects Layer values whose input requirements (RIn) contain services that are not satisfied by the composed layers. Similar to missingEffectContext but for the layer graph.
import { Effect, Layer } from "effect"

class Config extends Effect.Service<Config>()("Config", {
  effect: Effect.succeed({ url: "http://localhost" })
}) {}

class HttpClient extends Effect.Service<HttpClient>()("HttpClient", {
  effect: Effect.gen(function* () {
    const config = yield* Config
    return { get: (path: string) => Effect.void }
  })
}) {}

// ❌ Violation — Config is required by HttpClient.Default but not provided
const AppLayer: Layer.Layer<HttpClient> = HttpClient.Default

// ✅ Correct — compose layers to satisfy requirements
const AppLayer: Layer.Layer<HttpClient> = HttpClient.Default.pipe(
  Layer.provide(Config.Default)
)

missingReturnYieldStar

Severity: ❌ error  ·  Fix: 🔧  ·  V3/V4: ✓ / ✓ Suggests using return yield* for Effects that never succeed (success type is never). Using return yield* instead of just yield* signals a definitive exit point, improving type narrowing and tooling support for exhaustive pattern matching.
import { Effect } from "effect"

// ❌ Violation — yield* on a never-succeeding effect without return
const handle = Effect.gen(function* () {
  const result = yield* someEffect
  if (result === null) {
    yield* Effect.fail(new Error("null result")) // missing return
  }
  return result
})

// ✅ Correct — return yield* signals the function exits here
const handle = Effect.gen(function* () {
  const result = yield* someEffect
  if (result === null) {
    return yield* Effect.fail(new Error("null result"))
  }
  return result
})

missingStarInYieldEffectGen

Severity: ❌ error  ·  Fix: 🔧  ·  V3/V4: ✓ / ✓ Detects bare yield (without *) inside Effect generator scopes. Inside Effect.gen, you must always use yield* to unwrap an Effect. Using yield without * returns the raw Effect object rather than executing it.
import { Effect } from "effect"

// ❌ Violation — bare yield, the effect is not executed
const program = Effect.gen(function* () {
  const value = yield Effect.succeed(42) // should be yield*
  return value
})

// ✅ Correct — yield* executes the effect and unwraps the value
const program = Effect.gen(function* () {
  const value = yield* Effect.succeed(42)
  return value
})

nonObjectEffectServiceType

Severity: ❌ error  ·  V3 only  ·  V4: Ensures that the service type in Effect.Service is an object type ({}) and not a primitive. Effect’s Context system requires object types to safely attach tag metadata. This rule is V3-only because V4’s ServiceMap.Service handles primitives differently.
import { Effect } from "effect"

// ❌ Violation — service type is a primitive string
class ApiKey extends Effect.Service<ApiKey>()("ApiKey", {
  succeed: "my-api-key" // string is a primitive
}) {}

// ✅ Correct — wrap the value in an object
class ApiKey extends Effect.Service<ApiKey>()("ApiKey", {
  succeed: { value: "my-api-key" }
}) {}

outdatedApi

Severity: ⚠️ warning  ·  V3: —  ·  V4 only Detects usage of APIs that were removed or renamed in Effect V4. The diagnostic message includes the V3 API that was used and guidance on the V4 replacement. This rule is only active when the language service detects an Effect V4 project.
import { Effect } from "effect"

// ❌ Violation — Effect.tryCatchPromise was renamed in V4
const result = Effect.tryCatchPromise(
  () => fetch("/api"),
  (e) => new Error(String(e))
)

// ✅ Correct — use the V4 API
const result = Effect.tryPromise({
  try: () => fetch("/api"),
  catch: (e) => new Error(String(e))
})

overriddenSchemaConstructor

Severity: ❌ error  ·  Fix: 🔧  ·  V3/V4: ✓ / ✓ Prevents overriding the constructor in classes that extend a Schema class (Schema.Class, Schema.TaggedClass, Schema.TaggedError, etc.). Overriding the constructor silently breaks the schema’s decoding behaviour. Use a static factory method instead.
import { Schema } from "effect"

// ❌ Violation — constructor override breaks decoding
class User extends Schema.Class<User>("User")({
  id: Schema.String,
  name: Schema.String,
}) {
  constructor(data: { id: string; name: string }) {
    super(data) // this silently breaks decoding
  }
}

// ✅ Correct — use a static factory method
class User extends Schema.Class<User>("User")({
  id: Schema.String,
  name: Schema.String,
}) {
  static make(data: { id: string; name: string }): User {
    return new User(data)
  }
}
The quick fix removes the constructor override and replaces it with a static new method.