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):

  1. Input validation – Validates arguments against inputSchema (if defined)
  2. Execution – Calls your run() implementation
  3. Output validation – Validates the return value against outputSchema using 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:

Summary

  • Automatic validation: Agent-Native validates action return values against outputSchema immediately after run() 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 ValidationError instances that prevent corrupted data from propagating to agents or UI components.
  • Coercion awareness: Zod's validate does not coerce by default; use z.coerce or z.preprocess for 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →