Skip to content

Strict Diagnostics

The strict diagnostics module validates your Effect programs against a set of rules that catch common issues - missing error types, unhandled parallel errors, potential fiber leaks, and more. Think of it as a linter purpose-built for Effect patterns.

import { analyze, validateStrict, formatDiagnostics } from "effect-analyzer"
import { Effect } from "effect"
const ir = await Effect.runPromise(analyze("./src/transfer.ts").single())
const result = validateStrict(ir)
console.log(result.valid) // true if no errors
console.log(result.errors) // Error-severity diagnostics
console.log(result.warnings) // Warning-severity diagnostics
const output = formatDiagnostics(result)
console.log(output)

The validator checks 10 rules:

RuleSeverityDescription
missing-error-typeerrorAn effect step that can fail has no declared error type
unknown-error-typewarningAn effect step has unknown as its error type
parallel-missing-errorserrorEffects inside Effect.all lack error types, making parallel failure behavior unclear
race-missing-errorserrorEffects inside Effect.race lack error types
effect-without-handlerwarningAn effect produces errors but no handler (catchAll, catchTag) exists
fiber-potential-leakwarningA fiber is forked but never joined or interrupted
resource-missing-scopewarningacquireRelease used outside an explicit Scope
unbounded-concurrencywarningEffect.all without a concurrency option - defaults to sequential but may be unintentional
unused-servicewarningA service is required but never used in the program body
dead-code-pathwarningA code path that can never execute (e.g., code after Effect.die)

Customize which rules are active:

const result = validateStrict(ir, {
requireErrors: true, // Enforce error type declarations (default: true)
requireParallelErrors: true, // Enforce error types in parallel/race (default: true)
warningsAsErrors: false, // Promote all warnings to errors (default: false)
})
OptionTypeDefaultDescription
requireErrorsbooleantrueRequire effect nodes to declare error types
requireParallelErrorsbooleantrueRequire error types specifically in parallel/race contexts
warningsAsErrorsbooleanfalseTreat warnings as errors (useful for strict CI)
import { formatDiagnostics } from "effect-analyzer"
const output = formatDiagnostics(result)
console.log(output)

Example output:

ERROR [missing-error-type] Step "getBalance" can fail but has no declared error type
at src/transfer.ts:15:5
Fix: Add an error type annotation or use Effect.catchAll
WARNING [fiber-potential-leak] Fiber forked at "backgroundSync" is never joined
at src/transfer.ts:42:3
Fix: Use Fiber.join or Effect.scoped to manage the fiber lifecycle
2 errors, 1 warning
import { formatDiagnosticsJSON } from "effect-analyzer"
const json = formatDiagnosticsJSON(result)
console.log(json)
import { getSummary } from "effect-analyzer"
const summary = getSummary(result)
console.log(summary)
// { errors: 2, warnings: 1, total: 3 }

Each StrictDiagnostic contains:

FieldTypeDescription
ruleStrictRuleThe rule that triggered this diagnostic
severity'error' | 'warning'Diagnostic severity
messagestringHuman-readable description
fixstring | undefinedSuggested fix
locationSourceLocation | undefinedFile, line, and column
nodeIdstring | undefinedIR node that triggered the diagnostic

Use warningsAsErrors: true and check result.valid in your CI pipeline:

const result = validateStrict(ir, { warningsAsErrors: true })
if (!result.valid) {
console.error(formatDiagnostics(result))
process.exit(1)
}