How Validation and Constraint Handling Works in Ax Signatures: A Complete Technical Guide
Ax validates signatures at construction time in src/ax/dsp/sig.ts to enforce field naming rules and type restrictions, then performs runtime validation in src/ax/dsp/validators.ts to check data against constraints like minLength, pattern, and format.
The ax-llm/ax library implements a rigorous two-phase validation system for DSPy signatures that ensures both syntactic correctness at definition time and semantic validation at runtime. Understanding how validation and constraint handling works in Ax signatures is essential for building reliable LLM pipelines that fail fast with clear, actionable error messages.
Two-Phase Validation Architecture
Ax separates validation into distinct construction-time and runtime phases. This separation allows the framework to catch schema errors immediately when you define a signature, while deferring data-specific constraint checks until actual values are processed.
Phase 1: Signature Construction Validation
When you instantiate a signature using new AxSignature('...') or AxSignature.create('...'), the parser generates a ParsedSignature and immediately validates every field definition. This phase ensures your signature schema is structurally sound before any data flows through it.
Phase 2: Runtime Data Validation
After an LLM generates a response, the DSP layer validates the parsed output against the constraints defined in the signature. This phase checks whether actual string lengths, numeric ranges, and format patterns satisfy the schema requirements.
Signature Construction Validation
Construction-time validation enforces naming conventions and type compatibility rules. The logic resides in src/ax/dsp/sig.ts within the validateField and validateFieldType functions.
Field Name Validation
Ax validates field names according to strict naming conventions:
- Names must be non-empty and adhere to camelCase or snake_case conventions
- Length limits prevent excessively long identifiers
- When
axGlobals.signatureStrictis enabled, reserved word checks prevent naming conflicts with internal keywords - Duplicate field names or names appearing in both input and output sections trigger an immediate
AxSignatureValidationError
Field Type Restrictions
The validateFieldType function enforces type-specific placement rules:
- Media types (
image,audio,file) are restricted to input fields only - Class types are restricted to output fields only and must contain a non-empty list of unique options
- Violations throw
AxSignatureValidationErrorwith specific suggestions for correction
Runtime Constraint Validation
Runtime validation occurs in src/ax/dsp/validators.ts, where specific constraint checkers verify data integrity against the schema defined during construction.
String Constraints
The validateStringConstraints function checks string fields against multiple constraint types:
minLengthandmaxLength: Enforce character count boundariespattern: Validates against regular expressionsformat: Checks specialized formats includingemailanduri/url
Number Constraints
The validateNumberConstraints function enforces numeric boundaries:
minimum: Sets the lower bound for numeric valuesmaximum: Sets the upper bound for numeric values
URL Format Validation
For fields specifying uri or url formats, the validateURL function attempts to parse the string using the JavaScript URL constructor. This ensures the value represents a valid, parseable URL before processing continues.
Error Handling and Reporting
Ax provides detailed error information through specialized error classes defined in src/ax/dsp/errors.ts.
Construction Errors
When signature construction fails, Ax throws AxSignatureValidationError containing:
- The problematic field name
- A human-readable description of the violation
- Suggestions for fixing the issue (such as correcting naming case or moving a field to the appropriate input/output section)
Runtime Errors
Runtime constraint violations generate specific errors via helper functions like createStringConstraintError and createNumberConstraintError. These errors include:
- The field that failed validation
- The constraint that was violated (e.g.,
minLength: 3) - The actual value received
This detailed error reporting enables automatic retry logic, where the framework can prompt the LLM to correct specific format violations based on the error details.
Practical Implementation Example
The following example demonstrates how to define constraints using the fluent builder API and how runtime validation catches violations:
import { f, AxSignature } from '@ax-llm/ax';
// Define a signature with multiple constraint types
const sig = f()
.input('email', f.string().email()) // email format validation
.input('age', f.number().min(18).max(120)) // number range validation
.input('username', f.string().min(3).max(20)) // string length validation
.output('welcomeMessage', f.string())
.build(); // validates field names & types at construction time
// Simulate an LLM response with constraint violations
const badResponse = {
welcomeMessage: 'Hello!',
age: 5, // violates minimum: 18
email: 'not-an-email', // violates email format
username: 'ab' // violates minLength: 3
};
try {
// Runtime validation walks each field and applies appropriate validators
const fields = sig.getOutputFields().concat(sig.getInputFields());
for (const field of fields) {
const value = (badResponse as any)[field.name];
if (field.type?.name === 'string') {
validateStringConstraints(value, field);
} else if (field.type?.name === 'number') {
validateNumberConstraints(value, field);
} else if (field.type?.format === 'uri' || field.type?.format === 'url') {
validateURL(value, field);
}
}
} catch (e) {
console.error('Validation failed:', (e as Error).message);
// Error contains specific field name and constraint violated
}
This example illustrates how Ax catches improper data before it reaches business logic, providing deterministic error messages that enable automatic correction prompts.
Summary
- Ax implements two-phase validation for signatures: construction-time checks in
src/ax/dsp/sig.tsand runtime checks insrc/ax/dsp/validators.ts. - Construction validation enforces field naming conventions (camelCase/snake_case, reserved words) and type placement rules (media types on input only, class types on output only).
- Runtime validation checks actual values against constraints including
minLength,maxLength,pattern,format(email/URL), and numeric ranges (minimum,maximum). - Detailed error reporting via
AxSignatureValidationErrorand constraint-specific errors enables automatic retry logic and clear debugging. - The fluent builder API (
f.string(),f.number(), etc.) attaches constraints to field definitions that the runtime validators enforce during execution.
Frequently Asked Questions
What is the difference between construction-time and runtime validation in Ax?
Construction-time validation occurs when you create a signature using new AxSignature() or the fluent builder. It checks field names for proper casing and reserved words, validates that media types appear only in inputs and class types only in outputs, and ensures no duplicate field names exist. Runtime validation happens when processing LLM responses, checking that actual data values satisfy constraints like string length, number ranges, and email formats.
How do I add string length constraints to an Ax signature field?
Use the fluent builder API to chain constraint methods when defining your field. For example, f.string().min(3).max(20) creates a string field that validates the value contains between 3 and 20 characters at runtime. You can also add pattern matching with .regex(/pattern/) or format validation with .email() or .url(). These constraints are stored in the field definition and enforced by validateStringConstraints in src/ax/dsp/validators.ts.
What happens when a runtime validation fails in Ax?
When a value violates a constraint, Ax throws a specific error created via the helper functions in src/ax/dsp/errors.ts. For example, violating a minimum length constraint triggers an error via createStringConstraintError, while numeric violations use createNumberConstraintError. These errors include the field name, the constraint violated, and the actual value received. This detailed information enables the framework to implement automatic retry logic, prompting the LLM to correct the specific format error.
Can I use media types like image in output fields?
No, media types including image, audio, and file are restricted to input fields only. During signature construction, the validateFieldType function in src/ax/dsp/sig.ts checks the field type against its placement. If you attempt to define an output field with a media type, Ax throws an AxSignatureValidationError indicating the type is only allowed on inputs. Conversely, the class type is restricted to output fields and requires a non-empty list of unique options.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →