# Model validation

> Apply structural model validation and inspect typed failures safely.

- Path: `Guides > Inference > Models > Model validation`
- Human: https://looprig.com/docs/guides/inference/models/validation
- Machine index: https://looprig.com/llms.txt

`Model.Validate` is the structural boundary before a descriptor enters a client. It returns typed errors and intentionally leaves provider policy to the consumer that owns a catalogue or codec registry.

## Validation rules

| Rule | Failure |
| --- | --- |
| `Name` is non-empty | `*ValidationError{Field: "Name"}` |
| `StructuredOutputWithTools` implies `Tools` and `StructuredOutput` | `*ValidationError{Field: "Caps.StructuredOutputWithTools"}` |
| Known max input/output limits do not exceed `WindowTokens` | `*ContextLimitsValidationError` |
| Non-empty base URL has a host and no userinfo | `*ValidationError{Field: "BaseURL"}` |
| Scheme is HTTPS, or loopback HTTP | `*ValidationError{Field: "BaseURL"}` |

Unknown `ProviderName` and `APIFormat` values pass. `OriginCustom` and `OriginCatalog` validate identically; origin changes downstream trust and gating, not the structural rules.

```go
descriptor := model.Model{BaseURL: "http://example.test", Name: "chat"}
err := descriptor.Validate()
var validation *model.ValidationError
if errors.As(err, &validation) {
	fmt.Println(validation.Field, validation.Reason)
}
```

Always use `errors.As` instead of matching the human-readable error string. A caller that needs a fully resolved identity should also call `descriptor.Key().Validate()`.

## Proof

- Source: [`inference/model/model.go`](https://github.com/looprig/inference/blob/main/model/model.go), [`inference/model/errors.go`](https://github.com/looprig/inference/blob/main/model/errors.go), [`inference/model/contextlimits.go`](https://github.com/looprig/inference/blob/main/model/contextlimits.go)
- Tests: [`inference/model/model_test.go`](https://github.com/looprig/inference/blob/main/model/model_test.go), [`inference/model/contextlimits_test.go`](https://github.com/looprig/inference/blob/main/model/contextlimits_test.go), [`inference/model/apiformat_test.go`](https://github.com/looprig/inference/blob/main/model/apiformat_test.go)

Related: [Custom models](/docs/guides/inference/models/custom-models.md), [Model identity](/docs/guides/inference/models/identity.md).
