Skip to content

feat: introduce unified SDKError type and ObservabilityError extension#1286

Merged
serikjensen merged 6 commits intomainfrom
SDK-509
Mar 19, 2026
Merged

feat: introduce unified SDKError type and ObservabilityError extension#1286
serikjensen merged 6 commits intomainfrom
SDK-509

Conversation

@serikjensen
Copy link
Copy Markdown
Member

@serikjensen serikjensen commented Mar 18, 2026

Summary

  • Introduces a universal SDKError type that normalizes all error scenarios (API, validation, network, internal) into a single structured shape with category, message, httpStatus, fieldErrors, and raw
  • Creates ObservabilityError extends SDKError with timestamp, componentName, and componentStack for telemetry — keeping the partner-facing type clean
  • normalizeToSDKError is a pure function of the error type with no options — classification is based solely on instanceof checks
  • Updates base infrastructure (useBaseSubmit, BaseComponent, BaseLayout) to use SDKError for component state and enrich with observability context only at emission sites
  • Updates components consuming field errors (FederalTaxes, StateTaxes, Taxes, PaySchedule) to derive field errors from SDKError.fieldErrors
  • Removes deprecated types (ObservabilityErrorType, ObservabilityErrorContext, createObservabilityError, includeOriginalError)
  • Rewrites integration guide documentation to align with new types

This is prep work for the upcoming hooks-based architecture (#1254) where partners will interact with SDKError directly.

Type Design

SDKError (partner-facing):

interface SDKError {
  category: 'api_error' | 'validation_error' | 'network_error' | 'internal_error'
  message: string
  httpStatus?: number
  fieldErrors: SDKFieldError[]
  raw?: unknown
}

ObservabilityError extends SDKError (telemetry):

interface ObservabilityError extends SDKError {
  timestamp: number
  componentName?: string
  componentStack?: string
}

Errors displaying as expected

Field errors

Screenshot 2026-03-19 at 2 06 09 PM

SDK Internal Error

Screenshot 2026-03-19 at 2 24 49 PM

Test plan

  • TypeScript compilation passes (npx tsc --noEmit)
  • ESLint passes on all changed files
  • Build succeeds (npm run build)
  • Sanitization tests pass (30 tests)
  • Verified live against local API: Employee.Profile, Employee.FederalTaxes, Employee.StateTaxes, Employee.Taxes, Company.PaySchedule — all submit successfully with 0 console errors

Made with Cursor

Copy link
Copy Markdown
Contributor

@jeffredodd jeffredodd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the improvement.

Adds a universal SDKError type that normalizes all error scenarios (API,
validation, network, internal) into a single structured shape with
category, message, httpStatus, fieldErrors, and raw error. This replaces
the fragmented error handling and prepares for the upcoming hooks-based
architecture where partners interact with errors directly.

ObservabilityError extends SDKError with timestamp, componentName, and
componentStack for telemetry — keeping the partner-facing type clean.

- normalizeToSDKError is a pure function of error type (no options)
- Base infrastructure updated to use SDKError for component state
- Observability layer enriches with context at emission sites
- Removed deprecated types and createObservabilityError
- Updated integration guide documentation

Made-with: Cursor
…alization RFC

- SDKInternalError class for guard clauses inside baseSubmitHandler
  callbacks — surfaces as inline banner instead of ErrorBoundary crash
- normalizeToSDKError now parses APIError.httpMeta.body to recover
  structured field errors from untyped HTTP error responses (500s, 403s)
- Handles both snake_case (error_key) and camelCase (errorKey) field
  names from raw API JSON bodies
- Converts throw sites in OffCycleCreation, Profile, ContractorProfile,
  and PayrollConfiguration to use SDKInternalError
- Adds sdkError.test.ts with 14 tests covering all normalizeToSDKError
  branches including body parsing edge cases
- Adds RFC proposing the SDKError normalization approach

Made-with: Cursor
BaseLayout was always showing the hardcoded "Unknown Error" translation
for non-field, non-validation errors. Now renders error.message when
available, falling back to the generic string only when message is empty.

Made-with: Cursor
@serikjensen serikjensen enabled auto-merge (squash) March 19, 2026 22:19
…xist

buildApiErrorMessage now returns "N fields have issues" (or "1 field has
issues") instead of echoing the first field error message. This avoids
redundancy when message is displayed alongside the field error list and
gives partners a consistent summary string for logging and custom UI.

Made-with: Cursor
@serikjensen serikjensen merged commit beb374c into main Mar 19, 2026
14 checks passed
@serikjensen serikjensen deleted the SDK-509 branch March 19, 2026 22:22
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.

3 participants