# How to Implement Output Schema Validation for Agent Action Return Values in Agent-Native

> Learn to implement output schema validation for Agent-Native action return values. Ensure data integrity and catch errors automatically with Agent-Native's built-in validation.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-07-02

---

**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`](https://github.com/BuilderIO/agent-native/blob/main/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`](https://github.com/BuilderIO/agent-native/blob/main/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.

```typescript
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.

```typescript
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.

```typescript
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`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/action.ts)** (lines 311–644): Core validation wrapper that orchestrates the input→run→output sequence
- **[`packages/core/src/action.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/action.ts)** (lines 546–1315): Standard Schema normalization and the `~standard.validate()` invocation logic
- **[`packages/core/src/action.spec.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/action.spec.ts)** (lines 436–555): Comprehensive test suite covering successful validation, failure scenarios, and legacy mode backward compatibility
- **[`packages/core/src/action-ui.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/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 `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.