# OmniRoute Combo Schema Validation: A Complete Guide to Zod Constraints and Rules

> OmniRoute combo schema validation uses Zod to enforce strict constraints on naming, model steps, configuration, and routing before database entry. Learn about Zod rules.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-09

---

**OmniRoute validates all combo configurations using comprehensive Zod schemas located in [`src/shared/validation/schemas/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/schemas/combo.ts), enforcing strict constraints on naming, model steps, runtime configuration, and routing strategies before any data reaches the database.**

Every routing configuration in the OmniRoute open-source repository is governed by a robust validation layer that ensures type safety and data integrity. Whether you are creating combos via the REST API, CLI, or UI, the system applies server-side validation through Zod schemas that define precise boundaries for strings, numbers, enums, and nested objects. This validation guarantees that the routing engine receives only well-formed configurations, preventing runtime errors and ensuring consistent behavior across the multi-provider inference pipeline.

## Core Validation Layers

The validation logic in OmniRoute is modular, with specific schemas dedicated to distinct aspects of combo configuration. Each layer targets a particular data structure, from simple name strings to complex runtime configurations.

### Combo Name Validation

The **`comboNameSchema`** enforces strict naming conventions for all combo definitions. According to the source code in [`src/shared/validation/schemas/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/schemas/combo.ts), combo names must be between 1 and 100 characters after trimming, and may only contain letters, numbers, spaces, and the special characters `- _ / . [ ]`. The schema automatically trims whitespace and rejects empty strings, ensuring that every combo has a readable, URL-safe identifier.

### Model Step Validation

Individual steps within a combo are validated by **`comboModelStepInputSchema`**. This schema requires a `model` string (1–300 characters) and accepts optional fields including `provider`, `providerId`, and `connectionId`. The `prompt` field—representing system instructions—accepts up to 20,000 characters. Weight and metadata constraints are inherited from `comboStepMetaSchema`, which restricts weights to the 0–100 range and labels to 200 characters maximum.

For steps that reference other combos rather than direct models, **`comboRefStepInputSchema`** validates the `comboName` field (1–100 characters) and applies the same metadata constraints as model steps.

The **`comboModelEntry`** schema acts as a union validator, accepting either a plain string (legacy format), a full `comboModelStepInputSchema` object, or a `comboRefStepInputSchema` object, providing backward compatibility while encouraging structured configurations.

### Runtime Configuration Constraints

The **`comboRuntimeConfigSchema`** is the most comprehensive validator in the system, containing all tunable knobs for combo execution. It enforces numeric ranges such as `maxRetries` (0–10), `timeoutMs` (minimum 1,000), and `queueDepth` (maximum 100). The schema also validates queue limits (`concurrencyPerModel` ≤ 20) and boolean flags for session stickiness, health checks, and zero-latency optimizations.

Importantly, this schema uses `.passthrough()` to allow unknown keys for future-proofing, but implements a custom `.transform()` hook that automatically enables `zeroLatencyOptimizationsEnabled` when legacy flags like `hedging` or `predictiveTtftMs` are detected without the new flag being present.

### Shadow and Evaluation Routing

Optional advanced routing features have dedicated validators. **`shadowRoutingSchema`** validates the silent traffic duplication feature, ensuring `sampleRate` falls between 0 and 1, `maxTargets` stays within 1–10, and the `targets` array contains no more than 20 entries of `comboModelEntry`. The `timeoutMs` for shadow requests must be between 1,000 and 120,000 milliseconds.

For automated testing, **`evalRoutingSchema`** validates evaluation suite configurations. It accepts up to 50 `suiteIds` (each 1–200 characters), sets `maxAgeHours` between 1 and 8,760, and requires `minCases` between 1 and 100,000. Weighting fields are constrained to the 0–1 range.

### Strategy and Compression Enums

The **`comboStrategySchema`** restricts routing strategies to values exported from `ROUTING_STRATEGY_VALUES` in [`src/shared/constants/routingStrategies.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/routingStrategies.ts), preventing invalid algorithm selections.

Compression settings are governed by **`compressionModeSchema`**, which restricts values to the enum: `"off"`, `"lite"`, `"standard"`, `"aggressive"`, `"ultra"`, `"rtk"`, or `"stacked"`. The **`comboCompressionOverrideSchema`** extends this with an empty string option to represent "no override" configurations.

### Composite Tier Configuration

For hierarchical routing in composite combos, **`compositeTierEntrySchema`** and **`compositeTiersSchema`** validate tier structures. Each entry requires a `stepId` (≤ 200 characters) and supports optional fallback tiers, labels, and descriptions. The `defaultTier` field is mandatory, and the `tiers` property must be a record keyed by tier name.

### Response Validation Rules

The **`responseValidationSchema`** defines runtime checks for upstream provider responses, used primarily for fail-over logic. It validates `forbiddenSubstrings` and `requiredSubstrings` arrays (max 50 items each, each string ≤ 500 characters), sets `minContentLength` between 0 and 1,000,000 bytes, and restricts `jsonPathPredicates` to 20 objects with specific condition enums (`exists`, `nonEmpty`, `equals`, `notEquals`).

## CRUD Operation Schemas

### Creating New Combos

The **`createComboSchema`** validates payloads for POST `/api/combos` requests. It requires a `name` (validated by `comboNameSchema`), accepts an optional `description` (≤ 2,000 characters), and expects a `models` array of `comboModelEntry` items (defaulting to empty). The `strategy` field defaults to `"priority"`, while optional fields include `config` (runtime configuration), `allowedProviders`, `system_message`, and `tool_filter_regex`.

### Updating Existing Combos

For PATCH operations, **`updateComboSchema`** makes all fields optional but enforces a custom `superRefine` check that requires at least one field to be present. If no valid fields are provided, it returns the error "No valid fields to update". This schema additionally accepts a `compressionOverride` field not present in the creation schema.

### Global Defaults and Reordering

The **`updateComboDefaultsSchema`** validates updates to global combo defaults that affect all combos. It uses a custom `superRefine` to reject empty bodies and explicitly disallow `compositeTiers` on defaults or provider overrides, as hierarchical tiers are per-combo configurations.

For UI operations, **`reorderCombosSchema`** ensures that `comboIds` arrays contain unique identifiers (1–200 characters each) with a length between 1 and 1,000 items.

### Testing Combos

The **`testComboSchema`** supports the health-check endpoint by requiring a trimmed, non-empty `comboName` string.

## Schema Wiring and Backward Compatibility

The validation system uses composition to maintain consistency. The `comboStepMetaSchema` defines shared metadata fields (`id`, `weight`, `label`) that are spread into both model and reference step schemas using the spread operator (`...comboStepMetaSchema`).

The transform logic in `comboRuntimeConfigSchema` ensures backward compatibility by automatically injecting `zeroLatencyOptimizationsEnabled: true` when any legacy zero-latency flags are detected but the new unified flag is missing. This prevents stored configurations from failing validation after schema updates.

## Practical Validation Examples

### Creating a Simple Combo

```json
{
  "name": "my-first-combo",
  "description": "Demo combo that routes to OpenAI gpt‑4o.",
  "models": [
    {
      "model": "gpt-4o",
      "provider": "openai",
      "weight": 100,
      "prompt": "You are a helpful assistant."
    }
  ],
  "strategy": "priority",
  "config": {
    "maxRetries": 3,
    "timeoutMs": 30000,
    "compressionMode": "lite",
    "responseValidation": {
      "forbiddenSubstrings": ["error", "failed"],
      "minContentLength": 50
    }
  }
}

```

This payload satisfies all constraints: the name is ≤ 100 characters, the model string is ≤ 300 characters, the weight is within 0–100, timeout is ≥ 1,000 ms, compression uses an allowed enum value, and forbidden substrings are ≤ 500 characters each.

### Partial Update with Scoring Weights

```json
{
  "description": "Updated description with more detail.",
  "config": {
    "strategy": "weighted",
    "weights": {
      "quota": 0.4,
      "health": 0.2,
      "costInv": 0.1,
      "latencyInv": 0.1,
      "taskFit": 0.1,
      "stability": 0.1
    },
    "zeroLatencyOptimizationsEnabled": true
  }
}

```

The `updateComboSchema` accepts this partial payload because at least one field is present, and all numeric weights fall within the 0–1 range as enforced by `scoringWeightsSchema`.

### Advanced Configuration with Shadow and Eval Routing

```json
{
  "name": "shadow‑eval‑combo",
  "models": [
    { "model": "claude-3-5-sonnet", "provider": "anthropic", "weight": 80 },
    { "model": "gpt-4o-mini", "provider": "openai", "weight": 20 }
  ],
  "config": {
    "shadowRouting": {
      "enabled": true,
      "targets": [
        { "model": "gpt-4o-mini", "provider": "openai" }
      ],
      "sampleRate": 0.1,
      "maxTargets": 5,
      "timeoutMs": 20000
    },
    "evalRouting": {
      "enabled": true,
      "suiteIds": ["qa‑suite-01", "latency‑suite-02"],
      "maxAgeHours": 24,
      "minCases": 10
    }
  }
}

```

This configuration demonstrates the validation of shadow routing (with `sampleRate` between 0–1 and `maxTargets` ≤ 10) and evaluation routing (with `suiteIds` ≤ 50 and `maxAgeHours` ≤ 8,760).

## Key Source Files

- **[`src/shared/validation/schemas/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/schemas/combo.ts)** – Central Zod definitions for all combo validation including names, steps, runtime config, and overrides.
- **[`src/shared/constants/routingStrategies.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/routingStrategies.ts)** – Enum values used by `comboStrategySchema`.
- **[`src/shared/constants/batchEndpoints.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/batchEndpoints.ts)** – Constants for batch-endpoint validation in runtime config.
- **[`src/app/api/v1/combos/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/combos/route.ts)** – API route that applies Zod schemas to HTTP requests.

## Summary

- **OmniRoute validates all combo data** using Zod schemas in [`src/shared/validation/schemas/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/schemas/combo.ts) before database storage.
- **Name constraints** limit combo names to 1–100 characters with specific allowed characters and automatic trimming.
- **Step validation** supports both direct model references and nested combo references, with weights restricted to 0–100 and prompts up to 20,000 characters.
- **Runtime configuration** enforces numeric ranges for retries (0–10), timeouts (≥ 1,000 ms), and queue depths (≤ 100), while using `.passthrough()` and `.transform()` for backward compatibility.
- **Shadow and eval routing** schemas validate advanced features with strict bounds on sample rates, target counts, and suite configurations.
- **CRUD operations** use distinct schemas (`createComboSchema`, `updateComboSchema`, `updateComboDefaultsSchema`) with custom `superRefine` checks to prevent empty updates and invalid default configurations.

## Frequently Asked Questions

### What is the maximum length for a combo name in OmniRoute?

The **`comboNameSchema`** restricts combo names to between 1 and 100 characters after trimming. The validation also limits allowed characters to letters, numbers, spaces, and the specific symbols `- _ / . [ ]`, ensuring URL-safe and readable identifiers.

### How does OmniRoute handle backward compatibility when combo schemas change?

The system uses Zod's `.passthrough()` method to allow unknown keys in `comboRuntimeConfigSchema`, preventing immediate rejection of configs with legacy fields. Additionally, a custom `.transform()` hook automatically enables `zeroLatencyOptimizationsEnabled` when older zero-latency flags like `hedging` or `predictiveTtftMs` are present but the new flag is missing, ensuring stored combos remain valid after updates.

### What validation is applied to the `weights` field in a combo configuration?

The **`scoringWeightsSchema`** validates all scoring weights as numbers between 0 and 1. This schema applies to the auto-combo engine's weighting fields, including `tierPriority`, `tierAffinity`, `specificityMatch`, and `contextAffinity`, ensuring that the weighted routing algorithm receives normalized input values.

### Can I update a combo without providing all fields?

Yes. The **`updateComboSchema`** allows partial updates where all fields are optional, but it enforces a custom `superRefine` validation that requires at least one field to be present. If you submit an empty payload, the schema returns the error "No valid fields to update", preventing no-op database operations.