How to Implement Output Schema Validation for Agent Action Return Values in Agent-Native
Agent-Native automatically validates action return values against a declared outputSchema after the run() function executes, ensuring only properly structured data reaches callers while throwing ValidationError for mismatches.
Implementing output schema validation in Agent-Native (the open-source agent framework from BuilderIO/agent-native) ensures your agent actions return predictable, type-safe data. By defining an outputSchema when creating actions with defineAction, the framework validates return values at runtime using the Standard Schema specification (~standard), supporting both Zod and JSON Schema formats.
Understanding the Validation Flow
The validation mechanism wraps your action's execution in a strict pipeline that processes data in three distinct phases: input validation, execution, and output validation.
The Execution Order (Input → Run → Output)
When you invoke an action defined with defineAction, the framework executes a wrapper that enforces the following sequence as implemented in packages/core/src/action.ts (lines 311–644):
- Input validation – Validates arguments against
inputSchema(if defined) - Execution – Calls your
run()implementation - Output validation – Validates the return value against
outputSchemausing the schema's~standard.validate()method
If the output validation fails, the wrapper throws a ValidationError that propagates as an ActionError, preventing malformed data from reaching downstream consumers.
Standard Schema Implementation
The core runtime normalizes all schemas to the Standard Schema format (~standard) as shown in packages/core/src/action.ts (lines 546–1315). This abstraction allows the framework to treat Zod schemas, JSON Schemas, and other compatible validators uniformly. The wrapper invokes outputSchema["~standard"].validate(result) after run() resolves, returning the validated value (with any applied defaults or coercions) directly to the caller.
Implementing Output Schema Validation
Using Zod for Type-Safe Validation
Zod provides the most ergonomic approach for TypeScript developers, offering full type inference and detailed error messages.
import { defineAction } from "@agent-native/core";
import { z } from "zod";
export const fetchUserProfile = defineAction({
// Optional: input schema for the action parameters
inputSchema: z.object({
userId: z.string().uuid(),
}),
// Output schema validates the return value
outputSchema: z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
role: z.enum(["admin", "member"]).default("member"),
createdAt: z.coerce.date(),
}),
async run({ input }) {
// Simulate database fetch
const raw = await db.users.findUnique({
where: { id: input.userId }
});
// Return raw data - framework validates against outputSchema
return raw;
},
});
If the database returns a record missing the email field or with an invalid role, the action throws a ValidationError before the caller receives the data.
Using JSON Schema for Flexible Contracts
For interoperability with external systems or when you prefer JSON Schema syntax, pass a plain schema object that the runtime converts to the Standard Schema format.
import { defineAction } from "@agent-native/core";
const userOutputSchema = {
type: "object",
properties: {
id: { type: "string" },
name: { type: "string" },
email: { type: "string", format: "email" },
status: {
type: "string",
enum: ["active", "inactive"],
default: "active"
},
},
required: ["id", "name", "email"],
};
export const getUserStatus = defineAction({
outputSchema: userOutputSchema,
async run() {
const response = await externalApi.getUser();
return response; // Validated against JSON Schema
},
});
The framework automatically wraps this JSON Schema with a Standard Schema adapter before validation.
Handling Validation Errors
Always wrap action calls in try-catch blocks to handle potential validation failures gracefully.
try {
const user = await fetchUserProfile({ userId: "123e4567-e89b-12d3-a456-426614174000" });
console.log("Validated user:", user);
} catch (error) {
if (error.name === "ValidationError") {
console.error("Output validation failed:", error.errors);
// Handle schema mismatches (e.g., missing fields, type errors)
} else {
console.error("Execution error:", error);
}
}
Validation errors include detailed path information indicating exactly which fields failed validation and why.
Key Source Files and Implementation Details
The output validation system is implemented across these critical files in the BuilderIO/agent-native repository:
packages/core/src/action.ts(lines 311–644): Core validation wrapper that orchestrates the input→run→output sequencepackages/core/src/action.ts(lines 546–1315): Standard Schema normalization and the~standard.validate()invocation logicpackages/core/src/action.spec.ts(lines 436–555): Comprehensive test suite covering successful validation, failure scenarios, and legacy mode backward compatibilitypackages/core/src/action-ui.ts: UI layer that consumes validated action results, relying on the same output guarantees
Summary
- Automatic validation: Agent-Native validates action return values against
outputSchemaimmediately afterrun()resolves. - Schema flexibility: Support both Zod schemas (for TypeScript projects) and JSON Schemas (for cross-platform compatibility) via the Standard Schema (
~standard) interface. - Fail-fast behavior: Validation failures throw
ValidationErrorinstances that prevent corrupted data from propagating to agents or UI components. - Coercion awareness: Zod's
validatedoes not coerce by default; usez.coerceorz.preprocessfor type conversions, or rely on JSON Schema defaults. - Legacy compatibility: Actions defined with only output schemas (no input schemas) follow the same validation pathway without input checks.
Frequently Asked Questions
Can I use both input and output schemas on the same action?
Yes. The defineAction helper accepts both inputSchema and outputSchema simultaneously. The framework validates inputs before calling run() and validates the return value after run() completes. Both schemas use the same Standard Schema interface, so you can mix Zod for inputs and JSON Schema for outputs if needed.
What happens if my action returns data that doesn't match the output schema?
The action wrapper throws a ValidationError (exposed as an ActionError) containing detailed information about the schema mismatch, including the specific path and expected vs. actual types. This error propagates to the caller, allowing you to catch and handle data corruption issues at the source rather than downstream in your application.
Does output validation support default values and coercion?
Yes. When using Zod, default values defined with .default() are applied during validation. However, Zod does not coerce types automatically—you must explicitly use z.coerce.string() or z.preprocess() for type conversions. JSON Schema defaults are also respected when the runtime converts the schema to Standard Schema format.
Is output schema validation optional in Agent-Native?
Yes. The outputSchema property is optional in defineAction. If omitted, the action returns the raw result of run() without validation. However, for production agent systems, defining output schemas is strongly recommended to ensure contract stability between actions and consuming components.
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 →