# Errors and checks

> Handle errors and check templates before rendering.

When something goes wrong, `render` rejects with an error that says which template failed, where, and often how to fix it. `render` never returns half a page. [Streaming](https://kilnlang.com/docs/api/streaming/#errors-and-status-codes) works differently once part of the page is sent.

```text
KilnRenderError: Unknown variable "titel" in pages/page.kiln at line 4, column 9. Did you mean "title"?

  3 | {% block content %}
> 4 |   <h1>{{ titel }}</h1>
    |          ^^^^^
  5 | {% endblock %}
```

## Error types

There are two kinds of error, both exported from `@lucidkiln/core`:

- `KilnSyntaxError` means a template couldn't be parsed. Its `diagnostics` list every problem found, not just the first.
- `KilnRenderError` means something failed while rendering, such as a missing variable or a function that threw.

```ts
import { KilnRenderError, KilnSyntaxError } from "@lucidkiln/core";

try {
	return await kiln.render("pages/page", context);
} catch (error) {
	if (error instanceof KilnRenderError && error.cause instanceof NotFound) {
		return notFoundPage();
	}
	throw error;
}
```

A `KilnRenderError` has these properties:

| Property | Description |
| --- | --- |
| `code` | A stable code, such as `undefined-variable` or `limit-steps` |
| `template`, `line`, `column` | Where the error happened |
| `frame` | The lines of source around the error, with a marker |
| `templateStack` | The templates involved, from the page down to the one that failed |
| `cause` | The original error, when your code threw: one of your functions, a getter in your data, your loader or your cache store |

## Checking templates

`check` parses a template and returns its problems without rendering it. Pass the source as the second argument to check text that isn't saved yet, such as a template being edited in a CMS.

```ts
const diagnostics = await kiln.check("pages/home", draftSource);

for (const problem of diagnostics) {
	console.log(`${problem.start.line}:${problem.start.column} ${problem.message}`);
}
```

As well as syntax errors, `check` looks at the other templates this one uses, when their names are written out in full rather than built at render time. It reports:

- A template that doesn't exist, unless the `include` says `ignore missing`.
- An `include` or `component` that passes a prop the template doesn't declare, leaves out a required prop, or passes a written-out value of the wrong type, such as `variant: "danger"`.
- A page with `props` that extends a layout, when the layout needs a prop the page neither declares nor sets. The page only accepts its own props, so the layout could never get it. A page with a rest prop passes everything on, so it isn't reported.
- A warning for a variable that a template with `props` reads but doesn't declare, set or get from globals. Layouts may read their page's variables, so declare those as props to remove the warning.
- A warning, in the same templates, for a variable a macro reads that is neither one of its parameters nor a global. A macro can't see the template's variables.

It also warns about obsolete and inaccessible HTML, such as an image with no `alt`. See [HTML checks](https://kilnlang.com/docs/tooling/html-checks/).

Apart from missing templates and HTML checks, these checks follow strict mode, so they are skipped when `strict` is off. `check` only knows what a template is passed when it can see the call, so it doesn't report unknown variables in templates without `props`.

Each diagnostic has a `code`, a `message`, a `severity` of `"error"` or `"warning"`, the `template`, and `start` and `end` positions with a line and column. Codes are stable, so tools can match them.

## Analysing templates

`analyze` reports what a template uses: the variables it reads, its props, the variables it sets at its top level, the functions, filters and tests it calls, the templates it extends, includes or imports, and its blocks and macros. Use it to build tooling, or to work out which data a page depends on.

```ts
const analysis = await kiln.analyze("pages/post");

analysis.functions; // ["document"]
analysis.templates; // [{ kind: "extends", name: "layouts/base.kiln", ... }]
```

A name built at render time, such as `"sections/" ~ section.type`, is reported with a `name` of null.

## Reading the markup

`templateText` returns a template's source with every tag, output and comment, and the content of `verbatim`, replaced by spaces. Line breaks stay, so every offset, line and column still points at the same place. Hand it to HTML tools, such as a validator or an HTML language service, so they see only the markup you wrote.

```ts
import { templateText } from "@lucidkiln/core";

templateText('<a href="{{ url }}">{% if new %}New{% endif %}</a>');
// '<a href="         ">            New           </a>'
```
