mdcontext 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/.changeset/README.md +28 -0
  2. package/.changeset/config.json +11 -0
  3. package/.claude/settings.local.json +25 -0
  4. package/.github/workflows/ci.yml +83 -0
  5. package/.github/workflows/claude-code-review.yml +44 -0
  6. package/.github/workflows/claude.yml +85 -0
  7. package/.github/workflows/release.yml +113 -0
  8. package/.tldrignore +112 -0
  9. package/BACKLOG.md +338 -0
  10. package/CONTRIBUTING.md +186 -0
  11. package/NOTES/NOTES +44 -0
  12. package/README.md +434 -11
  13. package/biome.json +36 -0
  14. package/cspell.config.yaml +14 -0
  15. package/dist/chunk-23UPXDNL.js +3044 -0
  16. package/dist/chunk-2W7MO2DL.js +1366 -0
  17. package/dist/chunk-3NUAZGMA.js +1689 -0
  18. package/dist/chunk-7TOWB2XB.js +366 -0
  19. package/dist/chunk-7XOTOADQ.js +3065 -0
  20. package/dist/chunk-AH2PDM2K.js +3042 -0
  21. package/dist/chunk-BNXWSZ63.js +3742 -0
  22. package/dist/chunk-BTL5DJVU.js +3222 -0
  23. package/dist/chunk-HDHYG7E4.js +104 -0
  24. package/dist/chunk-HLR4KZBP.js +3234 -0
  25. package/dist/chunk-IP3FRFEB.js +1045 -0
  26. package/dist/chunk-KHU56VDO.js +3042 -0
  27. package/dist/chunk-KRYIFLQR.js +88 -0
  28. package/dist/chunk-LBSDNLEM.js +287 -0
  29. package/dist/chunk-MNTQ7HCP.js +2643 -0
  30. package/dist/chunk-MUJELQQ6.js +1387 -0
  31. package/dist/chunk-MXJGMSLV.js +2199 -0
  32. package/dist/chunk-N6QJGC3Z.js +2636 -0
  33. package/dist/chunk-OBELGBPM.js +1713 -0
  34. package/dist/chunk-OT7R5XTA.js +3192 -0
  35. package/dist/chunk-P7X4RA2T.js +106 -0
  36. package/dist/chunk-PIDUQNC2.js +3185 -0
  37. package/dist/chunk-POGCDIH4.js +3187 -0
  38. package/dist/chunk-PSIEOQGZ.js +3043 -0
  39. package/dist/chunk-PVRT3IHA.js +3238 -0
  40. package/dist/chunk-QNN4TT23.js +1430 -0
  41. package/dist/chunk-RE3R45RJ.js +3042 -0
  42. package/dist/chunk-S7E6TFX6.js +803 -0
  43. package/dist/chunk-SG6GLU4U.js +1378 -0
  44. package/dist/chunk-SJCDV2ST.js +274 -0
  45. package/dist/chunk-SYE5XLF3.js +104 -0
  46. package/dist/chunk-T5VLYBZD.js +103 -0
  47. package/dist/chunk-TOQB7VWU.js +3238 -0
  48. package/dist/chunk-VFNMZ4ZQ.js +3228 -0
  49. package/dist/chunk-VVTGZNBT.js +1629 -0
  50. package/dist/chunk-W7Q4RFEV.js +104 -0
  51. package/dist/chunk-XTYYVRLO.js +3190 -0
  52. package/dist/chunk-Y6MDYVJD.js +3063 -0
  53. package/dist/cli/main.d.ts +1 -0
  54. package/dist/cli/main.js +5458 -0
  55. package/dist/index.d.ts +653 -0
  56. package/dist/index.js +79 -0
  57. package/dist/mcp/server.d.ts +1 -0
  58. package/dist/mcp/server.js +472 -0
  59. package/dist/schema-BAWSG7KY.js +22 -0
  60. package/dist/schema-E3QUPL26.js +20 -0
  61. package/dist/schema-EHL7WUT6.js +20 -0
  62. package/docs/019-USAGE.md +625 -0
  63. package/docs/020-current-implementation.md +364 -0
  64. package/docs/021-DOGFOODING-FINDINGS.md +175 -0
  65. package/docs/BACKLOG.md +80 -0
  66. package/docs/CONFIG.md +1123 -0
  67. package/docs/DESIGN.md +439 -0
  68. package/docs/ERRORS.md +383 -0
  69. package/docs/PROJECT.md +88 -0
  70. package/docs/ROADMAP.md +407 -0
  71. package/docs/summarization.md +320 -0
  72. package/docs/test-links.md +9 -0
  73. package/justfile +40 -0
  74. package/package.json +74 -9
  75. package/pnpm-workspace.yaml +5 -0
  76. package/research/INDEX.md +315 -0
  77. package/research/code-review/README.md +90 -0
  78. package/research/code-review/cli-error-handling-review.md +979 -0
  79. package/research/code-review/code-review-validation-report.md +464 -0
  80. package/research/code-review/main-ts-review.md +1128 -0
  81. package/research/config-analysis/01-current-implementation.md +470 -0
  82. package/research/config-analysis/02-strategy-recommendation.md +428 -0
  83. package/research/config-analysis/03-task-candidates.md +715 -0
  84. package/research/config-analysis/033-research-configuration-management.md +828 -0
  85. package/research/config-analysis/034-research-effect-cli-config.md +1504 -0
  86. package/research/config-analysis/04-consolidated-task-candidates.md +277 -0
  87. package/research/config-docs/SUMMARY.md +357 -0
  88. package/research/config-docs/TEST-RESULTS.md +776 -0
  89. package/research/config-docs/TODO.md +542 -0
  90. package/research/config-docs/analysis.md +744 -0
  91. package/research/config-docs/fix-validation.md +502 -0
  92. package/research/config-docs/help-audit.md +264 -0
  93. package/research/config-docs/help-system-analysis.md +890 -0
  94. package/research/dogfood/consolidated-tool-evaluation.md +373 -0
  95. package/research/dogfood/strategy-a/a-synthesis.md +184 -0
  96. package/research/dogfood/strategy-a/a1-docs.md +226 -0
  97. package/research/dogfood/strategy-a/a2-amorphic.md +156 -0
  98. package/research/dogfood/strategy-a/a3-llm.md +164 -0
  99. package/research/dogfood/strategy-b/b-synthesis.md +228 -0
  100. package/research/dogfood/strategy-b/b1-architecture.md +207 -0
  101. package/research/dogfood/strategy-b/b2-gaps.md +258 -0
  102. package/research/dogfood/strategy-b/b3-workflows.md +250 -0
  103. package/research/dogfood/strategy-c/c-synthesis.md +451 -0
  104. package/research/dogfood/strategy-c/c1-explorer.md +192 -0
  105. package/research/dogfood/strategy-c/c2-diver-memory.md +145 -0
  106. package/research/dogfood/strategy-c/c3-diver-control.md +148 -0
  107. package/research/dogfood/strategy-c/c4-diver-failure.md +151 -0
  108. package/research/dogfood/strategy-c/c5-diver-execution.md +221 -0
  109. package/research/dogfood/strategy-c/c6-diver-org.md +221 -0
  110. package/research/effect-cli-error-handling.md +845 -0
  111. package/research/effect-errors-as-values.md +943 -0
  112. package/research/errors-task-analysis/00-consolidated-tasks.md +207 -0
  113. package/research/errors-task-analysis/cli-commands-analysis.md +909 -0
  114. package/research/errors-task-analysis/embeddings-analysis.md +709 -0
  115. package/research/errors-task-analysis/index-search-analysis.md +812 -0
  116. package/research/frontmatter/COMMENTS-ARE-SKIPPED.md +149 -0
  117. package/research/frontmatter/LLM-CODE-NAVIGATION.md +276 -0
  118. package/research/issue-review.md +603 -0
  119. package/research/llm-summarization/agent-cli-tools-2026.md +1082 -0
  120. package/research/llm-summarization/alternative-providers-2026.md +1428 -0
  121. package/research/llm-summarization/anthropic-2026.md +367 -0
  122. package/research/llm-summarization/claude-cli-integration.md +1706 -0
  123. package/research/llm-summarization/cli-integration-patterns.md +3155 -0
  124. package/research/llm-summarization/openai-2026.md +473 -0
  125. package/research/llm-summarization/openai-compatible-providers-2026.md +1022 -0
  126. package/research/llm-summarization/opencode-cli-integration.md +1552 -0
  127. package/research/llm-summarization/prompt-engineering-2026.md +1426 -0
  128. package/research/llm-summarization/prototype-results.md +56 -0
  129. package/research/llm-summarization/provider-switching-patterns-2026.md +2153 -0
  130. package/research/llm-summarization/typescript-llm-libraries-2026.md +2436 -0
  131. package/research/mdcontext-error-analysis.md +521 -0
  132. package/research/mdcontext-pudding/00-EXECUTIVE-SUMMARY.md +282 -0
  133. package/research/mdcontext-pudding/01-index-embed.md +956 -0
  134. package/research/mdcontext-pudding/02-search-COMMANDS.md +142 -0
  135. package/research/mdcontext-pudding/02-search-SUMMARY.md +146 -0
  136. package/research/mdcontext-pudding/02-search.md +970 -0
  137. package/research/mdcontext-pudding/03-context.md +779 -0
  138. package/research/mdcontext-pudding/04-navigation-and-analytics.md +803 -0
  139. package/research/mdcontext-pudding/04-tree.md +704 -0
  140. package/research/mdcontext-pudding/05-config.md +1038 -0
  141. package/research/mdcontext-pudding/06-links-summary.txt +87 -0
  142. package/research/mdcontext-pudding/06-links.md +679 -0
  143. package/research/mdcontext-pudding/07-stats.md +693 -0
  144. package/research/mdcontext-pudding/BUG-FIX-PLAN.md +388 -0
  145. package/research/mdcontext-pudding/P0-BUG-VALIDATION.md +167 -0
  146. package/research/mdcontext-pudding/README.md +168 -0
  147. package/research/mdcontext-pudding/TESTING-SUMMARY.md +128 -0
  148. package/research/npm_publish/011-npm-workflow-research-agent2.md +792 -0
  149. package/research/npm_publish/012-npm-workflow-research-agent1.md +530 -0
  150. package/research/npm_publish/013-npm-workflow-research-agent3.md +722 -0
  151. package/research/npm_publish/014-npm-workflow-synthesis.md +556 -0
  152. package/research/npm_publish/031-npm-workflow-task-analysis.md +134 -0
  153. package/research/research-quality-review.md +834 -0
  154. package/research/semantic-search/002-research-embedding-models.md +490 -0
  155. package/research/semantic-search/003-research-rag-alternatives.md +523 -0
  156. package/research/semantic-search/004-research-vector-search.md +841 -0
  157. package/research/semantic-search/032-research-semantic-search.md +427 -0
  158. package/research/semantic-search/embedding-text-analysis.md +156 -0
  159. package/research/semantic-search/multi-word-failure-reproduction.md +171 -0
  160. package/research/semantic-search/query-processing-analysis.md +207 -0
  161. package/research/semantic-search/root-cause-and-solution.md +114 -0
  162. package/research/semantic-search/threshold-validation-report.md +69 -0
  163. package/research/semantic-search/vector-search-analysis.md +63 -0
  164. package/research/task-management-2026/00-synthesis-recommendations.md +295 -0
  165. package/research/task-management-2026/01-ai-workflow-tools.md +416 -0
  166. package/research/task-management-2026/02-agent-framework-patterns.md +476 -0
  167. package/research/task-management-2026/03-lightweight-file-based.md +567 -0
  168. package/research/task-management-2026/04-established-tools-ai-features.md +541 -0
  169. package/research/task-management-2026/linear/01-core-features-workflow.md +771 -0
  170. package/research/task-management-2026/linear/02-api-integrations.md +930 -0
  171. package/research/task-management-2026/linear/03-ai-features.md +368 -0
  172. package/research/task-management-2026/linear/04-pricing-setup.md +205 -0
  173. package/research/task-management-2026/linear/05-usage-patterns-best-practices.md +605 -0
  174. package/research/test-path-issues.md +276 -0
  175. package/review/ALP-76/1-error-type-design.md +962 -0
  176. package/review/ALP-76/2-error-handling-patterns.md +906 -0
  177. package/review/ALP-76/3-error-presentation.md +624 -0
  178. package/review/ALP-76/4-test-coverage.md +625 -0
  179. package/review/ALP-76/5-migration-completeness.md +440 -0
  180. package/review/ALP-76/6-effect-best-practices.md +755 -0
  181. package/scripts/apply-branch-protection.sh +47 -0
  182. package/scripts/branch-protection-templates.json +79 -0
  183. package/scripts/prototype-summarization.ts +346 -0
  184. package/scripts/rebuild-hnswlib.js +58 -0
  185. package/scripts/setup-branch-protection.sh +64 -0
  186. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/active-provider.json +7 -0
  187. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.json +541 -0
  188. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.meta.json +5 -0
  189. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/config.json +8 -0
  190. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
  191. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
  192. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/documents.json +60 -0
  193. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/links.json +13 -0
  194. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/sections.json +1197 -0
  195. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/configuration-management.md +99 -0
  196. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/distributed-systems.md +92 -0
  197. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/error-handling.md +78 -0
  198. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/failure-automation.md +55 -0
  199. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/job-context.md +69 -0
  200. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/process-orchestration.md +99 -0
  201. package/src/cli/argv-preprocessor.test.ts +210 -0
  202. package/src/cli/argv-preprocessor.ts +202 -0
  203. package/src/cli/cli.test.ts +627 -0
  204. package/src/cli/commands/backlinks.ts +54 -0
  205. package/src/cli/commands/config-cmd.ts +642 -0
  206. package/src/cli/commands/context.ts +285 -0
  207. package/src/cli/commands/duplicates.ts +122 -0
  208. package/src/cli/commands/embeddings.ts +529 -0
  209. package/src/cli/commands/index-cmd.ts +480 -0
  210. package/src/cli/commands/index.ts +16 -0
  211. package/src/cli/commands/links.ts +52 -0
  212. package/src/cli/commands/search.ts +1281 -0
  213. package/src/cli/commands/stats.ts +149 -0
  214. package/src/cli/commands/tree.ts +128 -0
  215. package/src/cli/config-layer.ts +176 -0
  216. package/src/cli/error-handler.test.ts +235 -0
  217. package/src/cli/error-handler.ts +655 -0
  218. package/src/cli/flag-schemas.ts +341 -0
  219. package/src/cli/help.ts +588 -0
  220. package/src/cli/index.ts +9 -0
  221. package/src/cli/main.ts +435 -0
  222. package/src/cli/options.ts +41 -0
  223. package/src/cli/shared-error-handling.ts +199 -0
  224. package/src/cli/typo-suggester.test.ts +105 -0
  225. package/src/cli/typo-suggester.ts +130 -0
  226. package/src/cli/utils.ts +259 -0
  227. package/src/config/file-provider.test.ts +320 -0
  228. package/src/config/file-provider.ts +273 -0
  229. package/src/config/index.ts +72 -0
  230. package/src/config/integration.test.ts +667 -0
  231. package/src/config/precedence.test.ts +277 -0
  232. package/src/config/precedence.ts +451 -0
  233. package/src/config/schema.test.ts +414 -0
  234. package/src/config/schema.ts +603 -0
  235. package/src/config/service.test.ts +320 -0
  236. package/src/config/service.ts +243 -0
  237. package/src/config/testing.test.ts +264 -0
  238. package/src/config/testing.ts +110 -0
  239. package/src/core/index.ts +1 -0
  240. package/src/core/types.ts +113 -0
  241. package/src/duplicates/detector.test.ts +183 -0
  242. package/src/duplicates/detector.ts +414 -0
  243. package/src/duplicates/index.ts +18 -0
  244. package/src/embeddings/embedding-namespace.test.ts +300 -0
  245. package/src/embeddings/embedding-namespace.ts +947 -0
  246. package/src/embeddings/heading-boost.test.ts +222 -0
  247. package/src/embeddings/hnsw-build-options.test.ts +198 -0
  248. package/src/embeddings/hyde.test.ts +272 -0
  249. package/src/embeddings/hyde.ts +264 -0
  250. package/src/embeddings/index.ts +10 -0
  251. package/src/embeddings/openai-provider.ts +414 -0
  252. package/src/embeddings/pricing.json +22 -0
  253. package/src/embeddings/provider-constants.ts +204 -0
  254. package/src/embeddings/provider-errors.test.ts +967 -0
  255. package/src/embeddings/provider-errors.ts +565 -0
  256. package/src/embeddings/provider-factory.test.ts +240 -0
  257. package/src/embeddings/provider-factory.ts +225 -0
  258. package/src/embeddings/provider-integration.test.ts +788 -0
  259. package/src/embeddings/query-preprocessing.test.ts +187 -0
  260. package/src/embeddings/semantic-search-threshold.test.ts +508 -0
  261. package/src/embeddings/semantic-search.ts +1270 -0
  262. package/src/embeddings/types.ts +359 -0
  263. package/src/embeddings/vector-store.ts +708 -0
  264. package/src/embeddings/voyage-provider.ts +313 -0
  265. package/src/errors/errors.test.ts +845 -0
  266. package/src/errors/index.ts +533 -0
  267. package/src/index/ignore-patterns.test.ts +354 -0
  268. package/src/index/ignore-patterns.ts +305 -0
  269. package/src/index/index.ts +4 -0
  270. package/src/index/indexer.ts +684 -0
  271. package/src/index/storage.ts +260 -0
  272. package/src/index/types.ts +147 -0
  273. package/src/index/watcher.ts +189 -0
  274. package/src/index.ts +30 -0
  275. package/src/integration/search-keyword.test.ts +678 -0
  276. package/src/mcp/server.ts +612 -0
  277. package/src/parser/index.ts +1 -0
  278. package/src/parser/parser.test.ts +291 -0
  279. package/src/parser/parser.ts +394 -0
  280. package/src/parser/section-filter.test.ts +277 -0
  281. package/src/parser/section-filter.ts +392 -0
  282. package/src/search/__tests__/hybrid-search.test.ts +650 -0
  283. package/src/search/bm25-store.ts +366 -0
  284. package/src/search/cross-encoder.test.ts +253 -0
  285. package/src/search/cross-encoder.ts +406 -0
  286. package/src/search/fuzzy-search.test.ts +419 -0
  287. package/src/search/fuzzy-search.ts +273 -0
  288. package/src/search/hybrid-search.ts +448 -0
  289. package/src/search/path-matcher.test.ts +276 -0
  290. package/src/search/path-matcher.ts +33 -0
  291. package/src/search/query-parser.test.ts +260 -0
  292. package/src/search/query-parser.ts +319 -0
  293. package/src/search/searcher.test.ts +280 -0
  294. package/src/search/searcher.ts +724 -0
  295. package/src/search/wink-bm25.d.ts +30 -0
  296. package/src/summarization/cli-providers/claude.ts +202 -0
  297. package/src/summarization/cli-providers/detection.test.ts +273 -0
  298. package/src/summarization/cli-providers/detection.ts +118 -0
  299. package/src/summarization/cli-providers/index.ts +8 -0
  300. package/src/summarization/cost.test.ts +139 -0
  301. package/src/summarization/cost.ts +102 -0
  302. package/src/summarization/error-handler.test.ts +127 -0
  303. package/src/summarization/error-handler.ts +111 -0
  304. package/src/summarization/index.ts +102 -0
  305. package/src/summarization/pipeline.test.ts +498 -0
  306. package/src/summarization/pipeline.ts +231 -0
  307. package/src/summarization/prompts.test.ts +269 -0
  308. package/src/summarization/prompts.ts +133 -0
  309. package/src/summarization/provider-factory.test.ts +396 -0
  310. package/src/summarization/provider-factory.ts +178 -0
  311. package/src/summarization/types.ts +184 -0
  312. package/src/summarize/budget-bugs.test.ts +620 -0
  313. package/src/summarize/formatters.ts +419 -0
  314. package/src/summarize/index.ts +20 -0
  315. package/src/summarize/summarizer.test.ts +275 -0
  316. package/src/summarize/summarizer.ts +597 -0
  317. package/src/summarize/verify-bugs.test.ts +238 -0
  318. package/src/types/huggingface-transformers.d.ts +66 -0
  319. package/src/utils/index.ts +1 -0
  320. package/src/utils/tokens.test.ts +142 -0
  321. package/src/utils/tokens.ts +186 -0
  322. package/tests/fixtures/cli/.mdcontext/active-provider.json +7 -0
  323. package/tests/fixtures/cli/.mdcontext/config.json +8 -0
  324. package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
  325. package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
  326. package/tests/fixtures/cli/.mdcontext/indexes/documents.json +33 -0
  327. package/tests/fixtures/cli/.mdcontext/indexes/links.json +12 -0
  328. package/tests/fixtures/cli/.mdcontext/indexes/sections.json +247 -0
  329. package/tests/fixtures/cli/README.md +9 -0
  330. package/tests/fixtures/cli/api-reference.md +11 -0
  331. package/tests/fixtures/cli/getting-started.md +11 -0
  332. package/tests/integration/embed-index.test.ts +712 -0
  333. package/tests/integration/search-context.test.ts +469 -0
  334. package/tests/integration/search-semantic.test.ts +522 -0
  335. package/tsconfig.json +26 -0
  336. package/vitest.config.ts +16 -0
  337. package/vitest.setup.ts +12 -0
@@ -0,0 +1,943 @@
1
+ # Effect: Errors as Values Pattern
2
+
3
+ > A comprehensive guide to Effect's type-safe error handling system
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Core Concept: Errors as Values](#core-concept-errors-as-values)
8
+ 2. [Error Types in Effect](#error-types-in-effect)
9
+ 3. [Error Handling Patterns](#error-handling-patterns)
10
+ 4. [Best Practices for CLI Applications](#best-practices-for-cli-applications)
11
+ 5. [Anti-patterns to Avoid](#anti-patterns-to-avoid)
12
+ 6. [Sources](#sources)
13
+
14
+ ---
15
+
16
+ ## Core Concept: Errors as Values
17
+
18
+ ### The Problem with Traditional Error Handling
19
+
20
+ In traditional TypeScript, error handling relies on try/catch and thrown exceptions:
21
+
22
+ ```typescript
23
+ // Traditional TypeScript - no type safety for errors
24
+ function divide(a: number, b: number): number {
25
+ if (b === 0) {
26
+ throw new Error("Division by zero");
27
+ }
28
+ return a / b;
29
+ }
30
+
31
+ // The type signature gives NO indication this can fail
32
+ // TypeScript infers: (a: number, b: number) => number
33
+ ```
34
+
35
+ **Problems with this approach:**
36
+
37
+ - Type signatures don't indicate that functions can throw
38
+ - Impossible to know what errors a function might produce
39
+ - Easy to forget error handling as codebases grow
40
+ - No compile-time enforcement of error handling
41
+
42
+ ### Effect's Solution: Track Errors in the Type System
43
+
44
+ Effect treats errors as **first-class values** tracked in the type system through the `Effect<A, E, R>` type:
45
+
46
+ ```typescript
47
+ Effect<A, E, R>;
48
+ // ^ ^ ^
49
+ // | | └── R: Requirements (dependencies/context)
50
+ // | └───── E: Error type (what can go wrong)
51
+ // └──────── A: Success type (the result)
52
+ ```
53
+
54
+ **Key insight**: By making errors explicit in the type signature, you always know:
55
+
56
+ - What a function returns on success
57
+ - What errors it might produce
58
+ - What dependencies it requires
59
+
60
+ ### Effect vs Exceptions: A Comparison
61
+
62
+ ```typescript
63
+ // Traditional: errors are invisible in types
64
+ function parseJSON(str: string): unknown {
65
+ return JSON.parse(str); // Can throw SyntaxError!
66
+ }
67
+
68
+ // Effect: errors are visible and tracked
69
+ import { Effect } from "effect";
70
+
71
+ class ParseError extends Data.TaggedError("ParseError")<{
72
+ message: string;
73
+ }> {}
74
+
75
+ const parseJSON = (str: string): Effect.Effect<unknown, ParseError> =>
76
+ Effect.try({
77
+ try: () => JSON.parse(str),
78
+ catch: (e) => new ParseError({ message: String(e) }),
79
+ });
80
+ ```
81
+
82
+ ### Automatic Error Union Tracking
83
+
84
+ When you compose effects, Effect automatically tracks all possible errors as a union:
85
+
86
+ ```typescript
87
+ import { Effect, Data } from "effect"
88
+
89
+ class NetworkError extends Data.TaggedError("NetworkError")<{}> {}
90
+ class ValidationError extends Data.TaggedError("ValidationError")<{}> {}
91
+
92
+ const fetchData: Effect.Effect<Data, NetworkError> = // ...
93
+ const validateData: Effect.Effect<ValidData, ValidationError> = // ...
94
+
95
+ // Composed effect automatically has union error type
96
+ const program: Effect.Effect<ValidData, NetworkError | ValidationError> =
97
+ fetchData.pipe(
98
+ Effect.flatMap(data => validateData)
99
+ );
100
+ ```
101
+
102
+ ### Why This Matters
103
+
104
+ 1. **Compile-time safety**: The compiler forces you to handle all error cases
105
+ 2. **Exhaustive handling**: You can pattern match on error types
106
+ 3. **Self-documenting code**: Type signatures tell the full story
107
+ 4. **Refactoring confidence**: Change an error type and the compiler shows all affected code
108
+
109
+ ---
110
+
111
+ ## Error Types in Effect
112
+
113
+ ### Tagged Errors with Data.TaggedError
114
+
115
+ The recommended way to define errors in Effect is using `Data.TaggedError`:
116
+
117
+ ```typescript
118
+ import { Data } from "effect";
119
+
120
+ // Define custom errors with unique tags
121
+ class NetworkError extends Data.TaggedError("NetworkError")<{
122
+ url: string;
123
+ statusCode: number;
124
+ }> {}
125
+
126
+ class ValidationError extends Data.TaggedError("ValidationError")<{
127
+ field: string;
128
+ message: string;
129
+ }> {}
130
+
131
+ class FileNotFoundError extends Data.TaggedError("FileNotFoundError")<{
132
+ path: string;
133
+ }> {}
134
+ ```
135
+
136
+ **Key benefits of TaggedError:**
137
+
138
+ - Automatically adds a `_tag` discriminant field
139
+ - Includes `cause` and `stack` properties
140
+ - Can be used both as a value (`new NetworkError(...)`) and a type
141
+ - Enables precise error matching with `catchTag`
142
+
143
+ ### Error Hierarchies and Unions
144
+
145
+ Effect tracks error unions automatically, enabling hierarchical error handling:
146
+
147
+ ```typescript
148
+ // Domain-specific errors
149
+ class AuthError extends Data.TaggedError("AuthError")<{
150
+ reason: "invalid_token" | "expired" | "forbidden";
151
+ }> {}
152
+
153
+ class ApiError extends Data.TaggedError("ApiError")<{
154
+ endpoint: string;
155
+ statusCode: number;
156
+ }> {}
157
+
158
+ // Application-level error union
159
+ type AppError = AuthError | ApiError | ValidationError;
160
+
161
+ // Effect tracks these automatically
162
+ const fetchUser = (id: string): Effect.Effect<User, AuthError | ApiError> =>
163
+ // ...
164
+
165
+ const validateUser = (user: User): Effect.Effect<ValidUser, ValidationError> =>
166
+ // ...
167
+
168
+ // Composed: Effect<ValidUser, AuthError | ApiError | ValidationError>
169
+ const program = fetchUser("123").pipe(
170
+ Effect.flatMap(validateUser)
171
+ );
172
+ ```
173
+
174
+ ### The Three Types of Failures
175
+
176
+ Effect distinguishes between three fundamentally different failure modes:
177
+
178
+ #### 1. Expected Errors (Fail)
179
+
180
+ Errors that are part of your domain logic and should be handled:
181
+
182
+ ```typescript
183
+ import { Effect, Data } from "effect";
184
+
185
+ class InsufficientFundsError extends Data.TaggedError("InsufficientFunds")<{
186
+ balance: number;
187
+ required: number;
188
+ }> {}
189
+
190
+ const withdraw = (
191
+ amount: number,
192
+ ): Effect.Effect<number, InsufficientFundsError> =>
193
+ getBalance().pipe(
194
+ Effect.flatMap((balance) =>
195
+ balance < amount
196
+ ? Effect.fail(new InsufficientFundsError({ balance, required: amount }))
197
+ : Effect.succeed(balance - amount),
198
+ ),
199
+ );
200
+ ```
201
+
202
+ - Tracked in the `E` type parameter
203
+ - Should be handled with `catchTag`, `catchAll`, etc.
204
+ - Represent recoverable business logic failures
205
+
206
+ #### 2. Defects (Die)
207
+
208
+ Unexpected errors that indicate bugs or unrecoverable situations:
209
+
210
+ ```typescript
211
+ import { Effect } from "effect";
212
+
213
+ // Create a defect - unrecoverable error
214
+ const divide = (a: number, b: number): Effect.Effect<number> =>
215
+ b === 0
216
+ ? Effect.die(new Error("Division by zero - this should never happen"))
217
+ : Effect.succeed(a / b);
218
+
219
+ // Defects don't appear in the error type parameter!
220
+ // The effect type is Effect<number, never>
221
+ ```
222
+
223
+ - NOT tracked in the `E` type parameter (type is `never`)
224
+ - Indicate programming errors or impossible states
225
+ - Should NOT be recovered from in normal operation
226
+ - Can be caught with `catchAllDefect` for edge cases (e.g., plugin systems)
227
+
228
+ #### 3. Interruptions (Interrupt)
229
+
230
+ Represent fiber cancellation:
231
+
232
+ ```typescript
233
+ import { Effect, Fiber } from "effect";
234
+
235
+ // A long-running operation
236
+ const longTask = Effect.delay(Effect.succeed("done"), 10000);
237
+
238
+ // Interruption occurs when the result is no longer needed
239
+ const program = Effect.gen(function* () {
240
+ const fiber = yield* Effect.fork(longTask);
241
+ yield* Effect.sleep(100);
242
+ yield* Fiber.interrupt(fiber); // Interrupt the fiber
243
+ });
244
+ ```
245
+
246
+ - Occur when an Effect is cancelled
247
+ - Used for resource cleanup and timeout handling
248
+ - Can be handled with `Effect.onInterrupt`
249
+
250
+ ### The Cause Type: Lossless Error Information
251
+
252
+ Effect uses `Cause<E>` to preserve complete failure information:
253
+
254
+ ```typescript
255
+ import { Effect, Cause } from "effect";
256
+
257
+ const program = Effect.gen(function* () {
258
+ const cause = yield* Effect.cause(
259
+ Effect.all([
260
+ Effect.fail("error 1"),
261
+ Effect.die("defect"),
262
+ Effect.fail("error 2"),
263
+ ]),
264
+ );
265
+
266
+ // Extract just failures
267
+ console.log(Cause.failures(cause));
268
+ // { _id: 'Chunk', values: [ 'error 1', 'error 2' ] }
269
+
270
+ // Extract just defects
271
+ console.log(Cause.defects(cause));
272
+ // { _id: 'Chunk', values: [ 'defect' ] }
273
+ });
274
+ ```
275
+
276
+ Cause types include:
277
+
278
+ - `Cause.fail(E)` - Expected error
279
+ - `Cause.die(unknown)` - Defect/unexpected error
280
+ - `Cause.interrupt(FiberId)` - Fiber interruption
281
+ - `Cause.sequential(cause1, cause2)` - Sequential failure composition
282
+ - `Cause.parallel(cause1, cause2)` - Parallel failure composition
283
+
284
+ ---
285
+
286
+ ## Error Handling Patterns
287
+
288
+ ### Pattern 1: catchTag - Handle Specific Tagged Errors
289
+
290
+ Use `catchTag` to handle one specific error type:
291
+
292
+ ```typescript
293
+ import { Effect, Data } from "effect"
294
+
295
+ class NetworkError extends Data.TaggedError("NetworkError")<{
296
+ message: string;
297
+ }> {}
298
+
299
+ class ValidationError extends Data.TaggedError("ValidationError")<{
300
+ field: string;
301
+ }> {}
302
+
303
+ const program: Effect.Effect<string, NetworkError | ValidationError> = // ...
304
+
305
+ // Handle only NetworkError, ValidationError still propagates
306
+ const handled = program.pipe(
307
+ Effect.catchTag("NetworkError", (error) =>
308
+ Effect.succeed(`Network failed: ${error.message}`)
309
+ )
310
+ );
311
+ // Type: Effect<string, ValidationError>
312
+ ```
313
+
314
+ ### Pattern 2: catchTags - Exhaustive Pattern Matching
315
+
316
+ Handle all tagged errors in a single block:
317
+
318
+ ```typescript
319
+ const fullyHandled = program.pipe(
320
+ Effect.catchTags({
321
+ NetworkError: (error) => Effect.succeed(`Network failed: ${error.message}`),
322
+ ValidationError: (error) =>
323
+ Effect.succeed(`Validation failed on ${error.field}`),
324
+ }),
325
+ );
326
+ // Type: Effect<string, never>
327
+ // Error channel is 'never' - all errors handled!
328
+ ```
329
+
330
+ ### Pattern 3: catchAll - Handle All Errors
331
+
332
+ Catch any error, regardless of type:
333
+
334
+ ```typescript
335
+ const recovered = program.pipe(
336
+ Effect.catchAll((error) => Effect.succeed("Fallback value")),
337
+ );
338
+ // Type: Effect<string, never>
339
+ ```
340
+
341
+ ### Pattern 4: catchSome - Conditional Error Handling
342
+
343
+ Handle errors that match a predicate:
344
+
345
+ ```typescript
346
+ const partiallyHandled = program.pipe(
347
+ Effect.catchSome((error) => {
348
+ if (error._tag === "NetworkError" && error.statusCode === 404) {
349
+ return Option.some(Effect.succeed("Not found, using default"));
350
+ }
351
+ return Option.none(); // Let other errors propagate
352
+ }),
353
+ );
354
+ ```
355
+
356
+ ### Pattern 5: catchIf - Predicate-Based Handling
357
+
358
+ ```typescript
359
+ const handled = program.pipe(
360
+ Effect.catchIf(
361
+ (error): error is NetworkError => error._tag === "NetworkError",
362
+ (networkError) => Effect.succeed(`Handled: ${networkError.message}`),
363
+ ),
364
+ );
365
+ ```
366
+
367
+ ### Pattern 6: mapError - Transform Error Types
368
+
369
+ Transform errors without handling them:
370
+
371
+ ```typescript
372
+ class AppError extends Data.TaggedError("AppError")<{
373
+ originalError: unknown;
374
+ context: string;
375
+ }> {}
376
+
377
+ const mapped = program.pipe(
378
+ Effect.mapError(
379
+ (error) =>
380
+ new AppError({
381
+ originalError: error,
382
+ context: "User fetch operation",
383
+ }),
384
+ ),
385
+ );
386
+ // Type: Effect<string, AppError>
387
+ ```
388
+
389
+ ### Pattern 7: orElse - Provide Fallback Effects
390
+
391
+ ```typescript
392
+ const primary: Effect.Effect<User, NetworkError> = fetchUser("123");
393
+ const fallback: Effect.Effect<User, CacheError> = getCachedUser("123");
394
+
395
+ const withFallback = primary.pipe(Effect.orElse(() => fallback));
396
+ // Type: Effect<User, CacheError>
397
+ // Primary's error is replaced if it fails
398
+ ```
399
+
400
+ ### Pattern 8: orElseFail - Replace with Different Error
401
+
402
+ ```typescript
403
+ class UserNotAvailableError extends Data.TaggedError("UserNotAvailable")<{}> {}
404
+
405
+ const standardized = program.pipe(
406
+ Effect.orElseFail(() => new UserNotAvailableError()),
407
+ );
408
+ // All original errors become UserNotAvailableError
409
+ ```
410
+
411
+ ### Pattern 9: orElseSucceed - Provide Default Value
412
+
413
+ ```typescript
414
+ const withDefault = fetchUser("123").pipe(
415
+ Effect.orElseSucceed(() => ({ name: "Anonymous", id: "0" })),
416
+ );
417
+ // Type: Effect<User, never>
418
+ // Error channel becomes 'never' - always succeeds
419
+ ```
420
+
421
+ ### Pattern 10: retry - Automatic Retries
422
+
423
+ ```typescript
424
+ import { Effect, Schedule } from "effect"
425
+
426
+ const task: Effect.Effect<string, NetworkError> = // ...
427
+
428
+ // Retry up to 3 times
429
+ const retried = task.pipe(
430
+ Effect.retry({ times: 3 })
431
+ );
432
+
433
+ // Retry with exponential backoff
434
+ const withBackoff = task.pipe(
435
+ Effect.retry(Schedule.exponential("100 millis"))
436
+ );
437
+
438
+ // Retry only for specific errors
439
+ const selectiveRetry = task.pipe(
440
+ Effect.retry({
441
+ times: 3,
442
+ while: (error) => error._tag === "NetworkError"
443
+ })
444
+ );
445
+ ```
446
+
447
+ ### Pattern 11: retryOrElse - Retry with Fallback
448
+
449
+ ```typescript
450
+ const robustFetch = task.pipe(
451
+ Effect.retryOrElse({ times: 3 }, (error, retryCount) =>
452
+ Effect.succeed(`Failed after ${retryCount} retries: ${error.message}`),
453
+ ),
454
+ );
455
+ ```
456
+
457
+ ### Pattern 12: matchCause - Handle All Failure Types
458
+
459
+ Distinguish between failures, defects, and interruptions:
460
+
461
+ ```typescript
462
+ const program = Effect.matchCause(task, {
463
+ onFailure: (cause) => {
464
+ switch (cause._tag) {
465
+ case "Fail":
466
+ return `Expected error: ${cause.error.message}`;
467
+ case "Die":
468
+ return `Defect: ${cause.defect}`;
469
+ case "Interrupt":
470
+ return `Interrupted by fiber: ${cause.fiberId}`;
471
+ default:
472
+ return "Other failure";
473
+ }
474
+ },
475
+ onSuccess: (value) => `Success: ${value}`,
476
+ });
477
+ ```
478
+
479
+ ---
480
+
481
+ ## Best Practices for CLI Applications
482
+
483
+ ### 1. Define Domain-Specific Error Types
484
+
485
+ Create clear, tagged errors for your CLI's domain:
486
+
487
+ ```typescript
488
+ import { Data } from "effect";
489
+
490
+ // Input/parsing errors
491
+ class InvalidArgumentError extends Data.TaggedError("InvalidArgument")<{
492
+ argument: string;
493
+ expected: string;
494
+ received: string;
495
+ }> {}
496
+
497
+ class MissingRequiredOptionError extends Data.TaggedError(
498
+ "MissingRequiredOption",
499
+ )<{
500
+ option: string;
501
+ }> {}
502
+
503
+ // File system errors
504
+ class FileNotFoundError extends Data.TaggedError("FileNotFound")<{
505
+ path: string;
506
+ }> {}
507
+
508
+ class PermissionDeniedError extends Data.TaggedError("PermissionDenied")<{
509
+ path: string;
510
+ operation: "read" | "write" | "execute";
511
+ }> {}
512
+
513
+ // Business logic errors
514
+ class ConfigurationError extends Data.TaggedError("ConfigurationError")<{
515
+ field: string;
516
+ message: string;
517
+ }> {}
518
+ ```
519
+
520
+ ### 2. Structured Error Data for Programmatic Handling
521
+
522
+ Include machine-readable data in errors:
523
+
524
+ ```typescript
525
+ class ProcessingError extends Data.TaggedError("ProcessingError")<{
526
+ // Human-readable
527
+ message: string;
528
+
529
+ // Machine-readable for programmatic handling
530
+ code: "PARSE_FAILED" | "VALIDATION_FAILED" | "TRANSFORM_FAILED";
531
+ file?: string;
532
+ line?: number;
533
+ column?: number;
534
+
535
+ // For debugging
536
+ cause?: unknown;
537
+ }> {}
538
+ ```
539
+
540
+ ### 3. Exit Codes Based on Error Type
541
+
542
+ Map errors to appropriate exit codes:
543
+
544
+ ```typescript
545
+ import { Effect, Exit, Cause } from "effect";
546
+
547
+ const EXIT_CODES = {
548
+ SUCCESS: 0,
549
+ GENERAL_ERROR: 1,
550
+ INVALID_ARGUMENT: 2,
551
+ FILE_NOT_FOUND: 3,
552
+ PERMISSION_DENIED: 4,
553
+ CONFIGURATION_ERROR: 5,
554
+ NETWORK_ERROR: 6,
555
+ INTERNAL_ERROR: 127,
556
+ } as const;
557
+
558
+ const getExitCode = (cause: Cause.Cause<AppError>): number => {
559
+ if (Cause.isFailType(cause)) {
560
+ const error = cause.error;
561
+ switch (error._tag) {
562
+ case "InvalidArgument":
563
+ case "MissingRequiredOption":
564
+ return EXIT_CODES.INVALID_ARGUMENT;
565
+ case "FileNotFound":
566
+ return EXIT_CODES.FILE_NOT_FOUND;
567
+ case "PermissionDenied":
568
+ return EXIT_CODES.PERMISSION_DENIED;
569
+ case "ConfigurationError":
570
+ return EXIT_CODES.CONFIGURATION_ERROR;
571
+ case "NetworkError":
572
+ return EXIT_CODES.NETWORK_ERROR;
573
+ default:
574
+ return EXIT_CODES.GENERAL_ERROR;
575
+ }
576
+ }
577
+ // Defects get internal error code
578
+ return EXIT_CODES.INTERNAL_ERROR;
579
+ };
580
+ ```
581
+
582
+ ### 4. User-Friendly Error Formatting
583
+
584
+ Format errors for human consumption at the application boundary:
585
+
586
+ ```typescript
587
+ import { Effect, Console } from "effect";
588
+
589
+ // Centralized error formatter
590
+ const formatErrorForUser = (error: AppError): string => {
591
+ switch (error._tag) {
592
+ case "FileNotFound":
593
+ return `Error: File not found: ${error.path}\n\nPlease check the path and try again.`;
594
+
595
+ case "InvalidArgument":
596
+ return (
597
+ `Error: Invalid value for '${error.argument}'\n` +
598
+ ` Expected: ${error.expected}\n` +
599
+ ` Received: ${error.received}`
600
+ );
601
+
602
+ case "ConfigurationError":
603
+ return `Configuration error in '${error.field}': ${error.message}`;
604
+
605
+ case "PermissionDenied":
606
+ return `Permission denied: Cannot ${error.operation} '${error.path}'`;
607
+
608
+ default:
609
+ return `Error: ${error.message}`;
610
+ }
611
+ };
612
+
613
+ // Apply formatting at the top level
614
+ const runCLI = (program: Effect.Effect<void, AppError>) =>
615
+ program.pipe(
616
+ Effect.catchAll((error) =>
617
+ Console.error(formatErrorForUser(error)).pipe(
618
+ Effect.flatMap(() => Effect.fail(error)), // Re-fail for exit code
619
+ ),
620
+ ),
621
+ );
622
+ ```
623
+
624
+ ### 5. Separate Error Presentation from Error Classes
625
+
626
+ Keep error classes clean - format at the boundary:
627
+
628
+ ```typescript
629
+ // Good: Error class is pure data
630
+ class ParseError extends Data.TaggedError("ParseError")<{
631
+ file: string;
632
+ line: number;
633
+ column: number;
634
+ message: string;
635
+ }> {}
636
+
637
+ // Format separately at the CLI boundary
638
+ const formatParseError = (error: ParseError): string =>
639
+ `Parse error in ${error.file}:${error.line}:${error.column}\n` +
640
+ ` ${error.message}`;
641
+ ```
642
+
643
+ ### 6. Preserve Error Context Through Transformations
644
+
645
+ When transforming errors, preserve the original cause:
646
+
647
+ ```typescript
648
+ class HighLevelError extends Data.TaggedError("HighLevelError")<{
649
+ operation: string;
650
+ cause: unknown;
651
+ }> {}
652
+
653
+ const operation = lowLevelEffect.pipe(
654
+ Effect.mapError(
655
+ (error) =>
656
+ new HighLevelError({
657
+ operation: "user fetch",
658
+ cause: error, // Preserve original error
659
+ }),
660
+ ),
661
+ );
662
+ ```
663
+
664
+ ### 7. Use Effect's Built-in Terminal Service
665
+
666
+ For CLI output, prefer Effect's Terminal service:
667
+
668
+ ```typescript
669
+ import { Effect, Terminal } from "@effect/platform";
670
+
671
+ const displayError = (error: AppError) =>
672
+ Effect.gen(function* () {
673
+ const terminal = yield* Terminal.Terminal;
674
+ yield* terminal.display(formatErrorForUser(error));
675
+ });
676
+ ```
677
+
678
+ ---
679
+
680
+ ## Anti-patterns to Avoid
681
+
682
+ ### Anti-pattern 1: console.error Inside Error Classes
683
+
684
+ **Bad:**
685
+
686
+ ```typescript
687
+ // DON'T: Side effects in error constructors
688
+ class BadError extends Data.TaggedError("BadError")<{
689
+ message: string;
690
+ }> {
691
+ constructor(props: { message: string }) {
692
+ super(props);
693
+ console.error(`Error: ${props.message}`); // Side effect!
694
+ }
695
+ }
696
+ ```
697
+
698
+ **Why it's bad:**
699
+
700
+ - Mixes presentation with data
701
+ - Cannot control when/how errors are displayed
702
+ - Breaks referential transparency
703
+ - Makes testing difficult
704
+ - Cannot format differently for different contexts (CLI vs JSON API)
705
+
706
+ **Good:**
707
+
708
+ ```typescript
709
+ // DO: Keep errors as pure data
710
+ class GoodError extends Data.TaggedError("GoodError")<{
711
+ message: string;
712
+ }> {}
713
+
714
+ // Format at the application boundary
715
+ const program = myEffect.pipe(
716
+ Effect.catchAll((error) => Console.error(formatError(error))),
717
+ );
718
+ ```
719
+
720
+ ### Anti-pattern 2: Converting Typed Errors to Generic Error Too Early
721
+
722
+ **Bad:**
723
+
724
+ ```typescript
725
+ // DON'T: Lose type information early
726
+ const fetchUser = (id: string) =>
727
+ Effect.tryPromise({
728
+ try: () => api.getUser(id),
729
+ catch: (e) => new Error(String(e)), // Lost all context!
730
+ });
731
+ ```
732
+
733
+ **Good:**
734
+
735
+ ```typescript
736
+ // DO: Preserve specific error types
737
+ const fetchUser = (id: string) =>
738
+ Effect.tryPromise({
739
+ try: () => api.getUser(id),
740
+ catch: (e) => {
741
+ if (e instanceof Response && e.status === 404) {
742
+ return new UserNotFoundError({ userId: id });
743
+ }
744
+ if (e instanceof Response && e.status === 401) {
745
+ return new UnauthorizedError({ resource: `user/${id}` });
746
+ }
747
+ return new NetworkError({
748
+ message: String(e),
749
+ endpoint: `/users/${id}`,
750
+ });
751
+ },
752
+ });
753
+ ```
754
+
755
+ ### Anti-pattern 3: Mixing Thrown Exceptions with Effect Errors
756
+
757
+ **Bad:**
758
+
759
+ ```typescript
760
+ // DON'T: Throw inside Effect
761
+ const process = Effect.sync(() => {
762
+ if (invalidCondition) {
763
+ throw new Error("Invalid!"); // Becomes a defect, not tracked!
764
+ }
765
+ return result;
766
+ });
767
+ ```
768
+
769
+ **Good:**
770
+
771
+ ```typescript
772
+ // DO: Use Effect.fail for expected errors
773
+ const process = Effect.gen(function* () {
774
+ if (invalidCondition) {
775
+ return yield* Effect.fail(new ValidationError({ reason: "invalid" }));
776
+ }
777
+ return result;
778
+ });
779
+ ```
780
+
781
+ ### Anti-pattern 4: Swallowing Errors
782
+
783
+ **Bad:**
784
+
785
+ ```typescript
786
+ // DON'T: Silently ignore errors
787
+ const risky = effect.pipe(
788
+ Effect.catchAll(() => Effect.succeed(undefined)), // Error vanished!
789
+ );
790
+ ```
791
+
792
+ **Good:**
793
+
794
+ ```typescript
795
+ // DO: Log or preserve error information
796
+ const risky = effect.pipe(
797
+ Effect.catchAll((error) =>
798
+ Effect.logWarning(`Operation failed: ${error._tag}`).pipe(
799
+ Effect.map(() => defaultValue),
800
+ ),
801
+ ),
802
+ );
803
+ ```
804
+
805
+ ### Anti-pattern 5: Losing Error Context in Transformations
806
+
807
+ **Bad:**
808
+
809
+ ```typescript
810
+ // DON'T: Throw away the original error
811
+ const mapped = effect.pipe(
812
+ Effect.mapError(() => new GenericError({ message: "Something failed" })),
813
+ );
814
+ ```
815
+
816
+ **Good:**
817
+
818
+ ```typescript
819
+ // DO: Preserve the cause chain
820
+ const mapped = effect.pipe(
821
+ Effect.mapError(
822
+ (original) =>
823
+ new HighLevelError({
824
+ message: "Operation failed",
825
+ cause: original, // Keep the original
826
+ }),
827
+ ),
828
+ );
829
+ ```
830
+
831
+ ### Anti-pattern 6: Not Using Tagged Errors
832
+
833
+ **Bad:**
834
+
835
+ ```typescript
836
+ // DON'T: Plain objects without tags
837
+ const fail = Effect.fail({ message: "error", code: 123 });
838
+ // Cannot use catchTag, hard to distinguish error types
839
+ ```
840
+
841
+ **Good:**
842
+
843
+ ```typescript
844
+ // DO: Use TaggedError for all domain errors
845
+ class ApiError extends Data.TaggedError("ApiError")<{
846
+ message: string;
847
+ code: number;
848
+ }> {}
849
+
850
+ const fail = Effect.fail(new ApiError({ message: "error", code: 123 }));
851
+ // Now catchTag works, types are clear
852
+ ```
853
+
854
+ ### Anti-pattern 7: Over-catching with catchAll
855
+
856
+ **Bad:**
857
+
858
+ ```typescript
859
+ // DON'T: Catch everything at low levels
860
+ const fetchData = fetchFromApi().pipe(
861
+ Effect.catchAll(() => Effect.succeed(defaultData)), // Hides ALL errors
862
+ );
863
+ ```
864
+
865
+ **Good:**
866
+
867
+ ```typescript
868
+ // DO: Handle specific errors, let others propagate
869
+ const fetchData = fetchFromApi().pipe(
870
+ Effect.catchTag(
871
+ "NetworkError",
872
+ (e) =>
873
+ e.statusCode === 404 ? Effect.succeed(defaultData) : Effect.fail(e), // Re-fail for other network errors
874
+ ),
875
+ // Other errors propagate up
876
+ );
877
+ ```
878
+
879
+ ### Anti-pattern 8: Using Defects for Expected Errors
880
+
881
+ **Bad:**
882
+
883
+ ```typescript
884
+ // DON'T: Use die for business logic errors
885
+ const validateAge = (age: number) =>
886
+ age < 0
887
+ ? Effect.die(new Error("Age cannot be negative")) // Wrong!
888
+ : Effect.succeed(age);
889
+ ```
890
+
891
+ **Good:**
892
+
893
+ ```typescript
894
+ // DO: Use fail for expected/recoverable errors
895
+ class InvalidAgeError extends Data.TaggedError("InvalidAge")<{
896
+ age: number;
897
+ }> {}
898
+
899
+ const validateAge = (age: number) =>
900
+ age < 0
901
+ ? Effect.fail(new InvalidAgeError({ age })) // Correct!
902
+ : Effect.succeed(age);
903
+ ```
904
+
905
+ ---
906
+
907
+ ## Sources
908
+
909
+ ### Official Documentation
910
+
911
+ - [Effect Documentation - Why Effect?](https://effect.website/docs/getting-started/why-effect/)
912
+ - [Effect Documentation - The Effect Type](https://effect.website/docs/getting-started/the-effect-type/)
913
+ - [Effect Documentation - Expected Errors](https://effect.website/docs/error-management/expected-errors/)
914
+ - [Effect Documentation - Unexpected Errors](https://effect.website/docs/error-management/unexpected-errors/)
915
+ - [Effect Documentation - Yieldable Errors](https://effect.website/docs/error-management/yieldable-errors/)
916
+ - [Effect Documentation - Error Channel Operations](https://effect.website/docs/error-management/error-channel-operations/)
917
+ - [Effect Documentation - Fallback](https://effect.website/docs/error-management/fallback/)
918
+ - [Effect Documentation - Retrying](https://effect.website/docs/error-management/retrying/)
919
+ - [Effect Documentation - Cause](https://effect.website/docs/data-types/cause/)
920
+ - [Effect Documentation - Data](https://effect.website/docs/data-types/data/)
921
+ - [Effect Documentation - Terminal](https://effect.website/docs/platform/terminal/)
922
+ - [Effect Documentation - Error Formatters](https://effect.website/docs/schema/error-formatters/)
923
+
924
+ ### Community Resources
925
+
926
+ - [TypeOnce - Define Errors with TaggedError](https://www.typeonce.dev/course/effect-beginners-complete-getting-started/type-safe-error-handling-with-effect/define-errors-with-taggederror)
927
+ - [Intro to Effect Part 2: Handling Errors](https://ybogomolov.me/02-effect-handling-errors)
928
+ - [How to Effect TS? - Best Practices](https://dtech.vision/blog/how-to-effect-ts-best-practices/)
929
+ - [Effect Patterns Repository](https://github.com/PaulJPhilp/EffectPatterns)
930
+ - [Exploring Effect in TypeScript - Tweag](https://www.tweag.io/blog/2024-11-07-typescript-effect/)
931
+ - [TypeScript Errors and Effect](https://davidmyno.rs/blog/typed-errors-and-effect/)
932
+ - [DeepWiki - Error Handling with Cause](https://deepwiki.com/Effect-TS/effect/2.5-error-handling-with-cause-either-and-option)
933
+
934
+ ### CLI Framework
935
+
936
+ - [@effect/cli npm package](https://www.npmjs.com/package/@effect/cli)
937
+ - [DeepWiki - CLI Framework](https://deepwiki.com/Effect-TS/effect/8.1-cli-framework)
938
+ - [Effect CLI README](https://github.com/Effect-TS/effect/blob/main/packages/cli/README.md)
939
+
940
+ ---
941
+
942
+ _Document created: 2026-01-22_
943
+ _Research scope: Effect's errors-as-values pattern for type-safe error handling_