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.