ContractError from synchronous prop validation, and async errors from useResource. Both are designed to be actionable — ContractError carries a structured JSON payload an AI agent can parse and act on directly, and useResource errors land in your component’s render state rather than crashing the process. This guide covers both, and shows how to close the loop between a generation error and a corrected re-generation.
ContractError basics
AContractError is thrown synchronously at the component call site the moment a prop contract is violated. It extends Error, so it behaves like any other thrown value — you catch it with try/catch.
ContractError JSON
Callerr.toJSON() on any ContractError to get a plain object that is safe to serialize, log, and pass to an AI agent without further processing.
fix field is written in plain English and targets the exact issue. An agent can read it directly without requiring additional context about the component or its schema.
Catching ContractErrors
Wrap any component call where props come from dynamic or agent-generated input. Checkerr.name === 'ContractError' to distinguish prop validation failures from unexpected runtime errors, then handle them separately.
ContractError fields
EveryContractError carries these fields on the instance and in toJSON():
| Field | Type | Description |
|---|---|---|
error | string | Always "ContractError". Use this to identify the error type when deserializing JSON payloads. |
component | string | The name of the component that threw — for example, "Button". |
prop | string | null | The prop that failed validation. null for component-level errors (e.g. registering a non-component). |
expected | string | What Solar expected — for example, "string" or "slot(Button)". |
received | string | What was actually passed — for example, "number" or "vnode with no _source". |
fix | string | A plain-English instruction for correcting the error. Safe to pass to an AI agent as-is. |
message | string | The full error message combining component, prop, expected, and received. |
Async errors from useResource
Errors fromuseResource do not throw — they land in the error field of the hook’s return value and trigger a re-render. Check error in your render function and return a fallback UI.
error is the raw Error object your fetch function threw — so error.message contains whatever message you set. Throw descriptive errors from your fetch function (new Error('HTTP 404'), new Error('Unauthorized')) so the message is useful in the UI and in logs.
If an in-flight request is aborted (because the key changed), the abort rejection is silently swallowed by
useResource. You will not see an error state from a cancellation — only from a genuine fetch failure. Design your error UI for real failures, not expected cancellations.Using errors for AI self-correction
ContractError’s structured toJSON() output is designed for this loop: generate code → run it → catch the error → feed it back → regenerate.
fix field in the error payload gives the agent a precise, actionable instruction. In practice, a single correction round resolves most prop type errors because the expected and received fields fully describe the mismatch.
Registry validation
registry.register() also throws a ContractError if you pass it a value that was not created with defineComponent(). This catches the common mistake of passing a plain function or object instead of a component.
defineComponent() before registry.register(). The _isComponent flag on the returned function is what registry.register() checks.
Solar warns for unknown props rather than throwing. If you pass a prop that is not declared in the component’s schema, Solar calls
console.warn — for example, "Button: unknown prop \"size\" passed but not declared in schema" — and continues rendering with the declared props. This keeps unknown-prop mistakes visible in the console without breaking the component.