# How `native check` Performs Markup Validation and Reports File:Line:Column Errors in Native SDK Apps

> Learn how native check validates markup in Vercel Native SDK apps. Get precise file:line:column error diagnostics without building.

- Repository: [Vercel Labs/native](https://github.com/vercel-labs/native)
- Tags: how-to-guide
- Published: 2026-07-18

---

**`native check` scans the `src/` directory for `.native` markup files, validates them via `markup_cli.checkFiles`, and emits precise `file:line:column` diagnostics that let developers jump straight to the source of any error—without ever building the app.**

As implemented in `vercel-labs/native`, the `native check` command provides fast, build-free validation for Native SDK applications. Its markup validation pipeline checks TypeScript cores, `.native` files, and the `app.zon` manifest while surfacing every issue with exact file, line, and column coordinates.

## The `native check` Markup Validation Pipeline

In `tools/native-sdk/main.zig`, the `native check` entry point orchestrates a six-stage pipeline that validates the whole app without producing a build.

### Locate the App Manifest

First, `native check` looks for an `app.zon` file in the current directory—or the directory you pass—to confirm it is inside a Native SDK app. If the file is missing, the command aborts immediately with a **MissingManifest** error.

### Run the TypeScript Core Checker

If the app uses a TypeScript core, `native check` runs the **@native-sdk/core subset checker** before any markup validation. This ensures TypeScript diagnostics are collected and reported alongside markup issues.

### Collect Markup Files

The command invokes **collectMarkupFiles**, defined in `tools/native-sdk/markup.zig`, to recursively walk `src/` and gather every file whose extension matches a markup file—specifically `.native`. The function returns a list of absolute paths that are fed into the validator.

### Validate Markup Files

The collected paths are passed to `markup_cli.checkFiles`. The validator returns a **CheckOutcome** structure containing the count of failures, warnings, and whether the **model-contract** was checked. This stage is where markup syntax and semantics are evaluated against the app's contract.

### Validate the Manifest

After markup checks, `app.zon` is parsed and validated using `tooling.manifest.validateFile` from `src/tooling/manifest.zig`. Any manifest problems are printed, and if validation fails, the command exits with an error.

### Report Results and Strict Mode

Finally, `native check` prints a one-line summary such as:

```bash
checked 3 markup files against the model contract, app.zon

```

If you pass the **`--strict`** flag, warnings are promoted to errors, causing the command to fail even when only warnings are present.

## File:Line:Column Error Format in Markup Diagnostics

When the markup compiler finds a problem, it prints diagnostics in a **file:line:column** format that editors and terminals can parse directly. According to the `vercel-labs/native` README:

> "`native check` validates every view … with **file:line:column** errors that teach."

The underlying diagnostics are generated by `src/primitives/canvas/ui_markup.zig`. Inside the markup compiler, the `printDiagnostic` logic attaches source locations to each node and formats them as `file:line:column` when emitting errors.

A typical CLI output looks like this:

```bash

# Example error output

src/app.native:12:5: unknown tag "buttonn" (did you mean "button"?)

```

This pinpoint output eliminates guesswork and allows IDEs to jump directly to the offending line and column.

## Running `native check` from the Command Line

You invoke the validator from inside an app directory. The following examples show the standard and strict modes:

```bash

# Validate TS core, markup, and app.zon

native check

# Promote warnings to errors

native check --strict

```

Because validation runs without a build step, the feedback loop is nearly instantaneous.

## Key Source Files Behind `native check`

Understanding the architecture is easier when you know which files handle each responsibility:

- **`tools/native-sdk/main.zig`** — The CLI entry point that orchestrates the core checker, markup validation, and manifest verification.
- **`tools/native-sdk/markup.zig`** — Implements `collectMarkupFiles` and the `CheckOutcome` structure; invokes the markup validator via `checkFiles`.
- **`src/primitives/canvas/ui_markup.zig`** — The markup compiler that parses `.native` files and emits diagnostics with file:line:column source locations through `printDiagnostic`.
- **`src/tooling/manifest.zig`** — Parses and validates `app.zon`, providing manifest-level diagnostics.

## Summary

- **`native check`** validates an entire Native SDK app without building it.
- The pipeline runs the TS core checker, collects `.native` files from `src/`, validates markup via `markup_cli.checkFiles`, and verifies `app.zon` through `tooling.manifest.validateFile`.
- Failures and warnings are aggregated in a `CheckOutcome`, and results are summarized on the command line.
- Diagnostics use a precise **file:line:column** format generated by `src/primitives/canvas/ui_markup.zig`, enabling direct navigation to errors.
- The **`--strict`** flag elevates warnings to errors for more stringent CI/CD gates.

## Frequently Asked Questions

### What does `native check` validate besides markup?

`native check` validates three layers: the TypeScript core (if the app uses one), every `.native` markup file under `src/`, and the `app.zon` manifest. Any failure in these layers causes the command to exit with an error.

### How does `native check` locate markup files to validate?

It calls `collectMarkupFiles` in `tools/native-sdk/markup.zig`, which recursively walks `src/` and selects every file with a `.native` extension. These absolute paths are then passed to the markup validator.

### What happens when `--strict` is passed to `native check`?

When `--strict` is used, all warnings collected in the `CheckOutcome` are promoted to errors. This guarantees that even minor markup or manifest issues will fail the command, which is useful for enforcing quality gates in continuous integration.

### Where are the file:line:column diagnostics generated?

The diagnostics are generated inside `src/primitives/canvas/ui_markup.zig` by the markup compiler. Its `printDiagnostic` logic maps each AST node back to its source location and formats the output as `file:line:column` so that editors and terminals can resolve the exact point of failure.