

# Handle validation errors [#handle-validation-errors]

Use this guide when calculator input comes from a form, API request or any
untyped source.

## Before you start [#before-you-start]

* Read [Type safety](/sdk/type-safety).
* Choose the SDK safe facade or the HTTP API error envelope.
* Keep canonical fact values tied to the selected calculator.

## Steps [#steps]

1. Prefer typed SDK helpers for trusted TypeScript data.
2. Decode external input with the selected calculator's input schema.
3. Use `TaxKit.safe.calculate` for checked input when calculation failures
   should be values.
4. Use `?help=errors` with HTTP calls when you want field guidance.
5. Display issue paths from the calculator error rather than maintaining a
   separate list of fields.

## Example [#example]

```ts
import { au } from "@taxkit/sdk/au";
import { Effect, Schema } from "effect";

// Check an external JSON representation before calling a typed calculator.
export const invalidInput = Schema.decodeEffect(
  Schema.fromJsonString(au.calculations.takeHomePay.inputSchema)
)('{"taxableIncome":{"_tag":"Money","cents":9000000,"currency":"AUD"}}');

export const validInput = Schema.decodeEffect(
  Schema.fromJsonString(au.calculations.takeHomePay.inputSchema)
)(
  '{"grossPay":{"_tag":"GrossPay","amount":{"_tag":"Money","cents":165400,"currency":"AUD"},"period":"weekly"},"taxFreeThresholdClaimed":true}'
).pipe(
  Effect.flatMap((input) => Effect.promise(() => au.pay.takeHomePay(input)))
);
```

## Verify the result [#verify-the-result]

`invalidInput` fails with `SchemaError` before a calculation runs because annual
income facts do not match the selected take-home calculator. `validInput`
returns the retained weekly fixture result: net pay of `130_100` cents.

Run these Effects at your application boundary. For checked TypeScript input,
use the [Safe SDK](/sdk/safe-sdk) and handle `TaxKitFailure` without an
unsafe cast. Its calculator error channel is separate from the initial check
of external input.

## HTTP error handling [#http-error-handling]

The typed HTTP client checks endpoint replies. If you read a raw HTTP response,
use the owning `CalculatorApiErrorEnvelope` decoder from [API errors](/api/errors).
Do not access fields on unchecked `response.json()` data.

## Related pages [#related-pages]

* [API errors](/api/errors)
* [Safe SDK](/sdk/safe-sdk)
* [Show calculator help to users](/guides/show-calculator-help-to-users)
