Errors reference
Every Attaform-emitted error class with the failure mode it represents, plus the small set of stable
codeidentifiers forValidationErrorentries Attaform produces.
- Category
- Reference
- Base class
AttaformError extends Error- Code prefix
atta:- Match by
- instanceof for classes, code for ValidationError
This page is reference material. Two surfaces: throw-class errors (caught with instanceof) and ValidationError.code strings (matched in template / handler logic). Both follow the atta: prefix convention for Attaform-emitted entries; consumer codes use whatever prefix you pick (api:, auth:, myapp:).
Catching errors polymorphically
Every Attaform-emitted throw extends AttaformError, so a single polymorphic catch works:
import { AttaformError } from 'attaform'
try {
// useForm setup, register call, persist call, etc.
} catch (err) {
if (err instanceof AttaformError) {
// It's one of ours; log and handle.
console.error('[attaform]', err.name, err.message)
} else {
throw err
}
}
Branch on the subclass for targeted handling:
import { AttaformError, OutsideSetupError, AnonPersistError } from 'attaform'
try {
// …
} catch (err) {
if (err instanceof OutsideSetupError) {
// Move the call into a Vue setup function
} else if (err instanceof AnonPersistError) {
// Pass a stable `key` so persistence has a deterministic prefix
} else if (err instanceof AttaformError) {
// Catch-all
} else {
throw err
}
}
Error classes
AttaformError
Base class; never thrown directly, only via subclasses. Provides the polymorphic-catch entry point.
class AttaformError extends Error {}
InvalidPathError
A path string can't be canonicalized against the form's schema. Typical cause: a typo in register('parh') or setValue('a.bb.c') against a schema with no .bb.
InvalidUseFormConfigError
useForm received an invalid configuration, most often a schema passed directly instead of inside an options object (useForm(schema) rather than useForm({ schema })).
SubmitErrorHandlerError
The onError callback passed to handleSubmit threw. Caught and re-thrown wrapped in this class so the wrapping submit lifecycle can distinguish "user error handler crashed" from "validation failed."
RegistryNotInstalledError
An Attaform API needs the registry attached to a Vue app, but it isn't installed. Auto-install kicks in for the lazy bootstrap path, so this usually means useRegistry() was called from outside a Vue app's lifecycle.
OutsideSetupError
useForm / injectForm / similar composable called outside Vue setup. Move the call inside a setup() function or <script setup> block.
ReservedFormKeyError
The __atta: namespace is reserved for internal use; passing a form key starting with __atta: throws. Pick a different prefix.
AnonPersistError
Persistence is configured on an anonymous (no key) form. The cause property distinguishes:
'no-key': nokeypassed; persistence needs a stable key to prefix storage entries.'register-without-config': a register call passes{ persist: true }against an anonymous form (which wouldn't have a backend even withpersist:on the form).
Carries schemaFields (the leaves on the form's schema, for diagnostic context) and callSite (the file:line of the offending call).
AttaformErrorCode
A small, stable enum for Attaform-emitted ValidationError.code values. The codes follow atta: prefix convention; pair with parseApiErrors to read the code field reactively in templates.
import { AttaformErrorCode } from 'attaform'
if (form.errors.email?.[0]?.code === AttaformErrorCode.NoValueSupplied) {
// …
}
| Code value | Constant | Emitted when |
|---|---|---|
atta:no-value-supplied | AttaformErrorCode.NoValueSupplied | A required leaf is in blankPaths (numeric auto-mark or unset). |
atta:adapter-threw | AttaformErrorCode.AdapterThrew | An AbstractSchema method (validate, getDefaults, etc.) threw. |
atta:validator-threw | AttaformErrorCode.ValidatorThrew | User code inside a z.preprocess / .refine / .transform threw. |
atta:hydration-failed | AttaformErrorCode.HydrationFailed | A function-form defaultValues factory threw or its promise rejected. |
atta:path-not-found | AttaformErrorCode.PathNotFound | A path canonicalization rejected the input as not reachable. |
atta:activation-failed | AttaformErrorCode.ActivationFailed | A walked form's async defaultValues factory threw inside wizard.handleSubmit. |
Don't expect every internal failure mode to surface as a stable code; the codes are reserved for cases where consumer templates legitimately want to branch on a specific failure mode without matching message strings.
The ValidationError shape
Every error in form.errors.<path>, form.meta.errors, and the parser's result has this shape:
type ValidationError = {
readonly path: ReadonlyArray<string | number>
readonly message: string
readonly code: string
readonly formKey: string
}
path: the canonical segment tuple (['profile', 'email']).message: the human-readable error text.code: stable identifier (atta:no-value-supplied,zod:invalid_type,api:duplicate-email, etc.).formKey: which form emitted the error. Useful for cross-form aggregation in wizards.
The code is what consumers branch on; the message is what templates render. Avoid matching message strings; they're localized and may change over time without breaking the public contract.
Code prefixes by source
| Prefix | Source |
|---|---|
atta: | Attaform-emitted (the AttaformErrorCode values). |
zod: | Zod adapter (computed from issue.code: zod:invalid_type, zod:too_small, etc.). |
api: | Conventional prefix for consumer-emitted server errors. Pick whatever convention fits the app: auth:, myapp:, etc. |
The prefix tells you where the error came from without parsing the rest of the string.
Where to next
parseApiErrors: generate consumer-codedValidationErrors from server responses.- The
blankfield-state bit: the side-channel that surfacesatta:no-value-supplied. - Server-side errors: the full flow from API failure to reactive
form.errors.