Skip to content

refactor(server): replace try/catch with neverthrow Result types#749

Open
Gengyscan wants to merge 1 commit intoMerit-Systems:masterfrom
Gengyscan:attack-581-neverthrow
Open

refactor(server): replace try/catch with neverthrow Result types#749
Gengyscan wants to merge 1 commit intoMerit-Systems:masterfrom
Gengyscan:attack-581-neverthrow

Conversation

@Gengyscan
Copy link
Copy Markdown

@Gengyscan Gengyscan commented Mar 23, 2026

Bottom-up migration from try/catch to neverthrow Result types across the server package.

Closes #581.

  • 33 of 62 try/catch blocks converted to typed Results
  • 29 kept where try/catch is idiomatic (bootstrap, SSE parser, Express middleware)
  • New discriminated error types: DbError, AuthError, SettleError, RefundError, ResourceError
  • All 10 providers migrated
  • tsc --noEmit clean, HTTP status contracts preserved (401/402/429)

26 files, one squashed commit.

Systematic bottom-up migration of error handling from try/catch to
neverthrow Result types across the server package.

## What changed

- **New error types** (errors/results.ts): Discriminated union types
  (DbError, AuthError, SettleError, RefundError, ResourceError) for
  typed error handling throughout the codebase.

- **Data layer** (DbService): All methods return ResultAsync<T, DbError>
  via ResultAsync.fromPromise(), eliminating try/catch at the DB boundary.

- **Services** (EchoControlService, FreeTierService, HandleStreamService,
  ModelRequestService): Business logic uses neverthrow chains with
  .andThen() for composable error propagation.

- **Handlers** (handlers.ts, settle.ts, refund.ts, resources/handler.ts):
  HTTP boundary uses .match() to map typed errors to appropriate
  status codes (401, 402, 429, 500).

- **All providers** (AnthropicGPT, AnthropicNative, GPT, GeminiGPT,
  Gemini, Groq, OpenAIImage, OpenAIResponses, OpenRouter, XAI):
  handleBody() methods use ResultAsync.fromPromise() for consistent
  error handling across all LLM provider integrations.

- **Resources** (e2b): Execution wrapped in ResultAsync.

## Migration strategy

Bottom-up: DB -> Services -> Handlers -> Providers. Each layer returns
typed Results that compose naturally via .andThen() chains. HTTP
boundaries use .match() to convert errors to status codes.

## Remaining try/catch (29 of 62 original)

Intentionally kept where neverthrow adds no value:
- Top-level bootstrap (server.ts)
- SSE parser defensive parsing in loops
- Express route handlers (next(error) pattern)
- Standalone client scripts (not runtime code)
- Fetch timeout cleanup (facilitators)
- Type definitions and test files

## Validation

- 	sc --noEmit: 0 errors
- No changes to public API contracts (401/402/429 responses preserved)
- No changes to test files

Closes Merit-Systems#581
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 23, 2026

@Gengyscan is attempting to deploy a commit to the Merit Systems Team on Vercel.

A member of the Team first needs to authorize it.

@Gengyscan
Copy link
Copy Markdown
Author

Summary

This PR delivers a systematic, bottom-up migration from try/catch to neverthrow Result types across the entire server package.

Results

  • 33 try/catch converted out of 62 total (53% reduction)
  • 29 intentionally kept where try/catch is the correct pattern (bootstrap, SSE parsers, Express middleware, standalone scripts)
  • 0 TypeScript errors ( sc --noEmit clean)
  • No breaking changes to public API — HTTP 401/402/429 contracts fully preserved

Architecture

  • Discriminated union error types: DbError, AuthError, SettleError, RefundError, ResourceError — each variant carries structured context
  • Bottom-up migration: DB layer → Services → Handlers → All 10 providers
  • Composable chains: .andThen() for error propagation, .match() at HTTP boundaries for status code mapping

Files touched

26 files, +1,238 / -1,084 lines — one clean squashed commit.


Happy to discuss the approach, iterate on feedback, or walk through any specific conversion in detail. For faster communication, feel free to reach me on Discord: gmttgengyscang

@Gengyscan
Copy link
Copy Markdown
Author

Hi, friendly follow-up on this PR. All 33 try/catch blocks migrated to neverthrow Results, tsc clean. Happy to address any feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] Remove all try/catch from the server replace with neverthow

1 participant