# Custom Views Compile Errors

> Every error the view compiler emits, with cause and fix

The CLI compiles every `.tsx` file under `views/` through an AST validator and then esbuild. Each error includes the source file, line, column, and a fix hint. This page is the catalogue.

## AST Validator Errors

### Imports

| Message | Cause | Fix |
|---------|-------|-----|
| `Imports must come from "struere/view". Found: "<source>".` | An import statement references a module other than `"struere/view"` | Replace with one or more named imports from `"struere/view"` |

### Raw HTML

| Message | Cause | Fix |
|---------|-------|-----|
| `Raw HTML element <name> is not allowed. Use a component from "struere/view" instead.` | A JSX tag starts with a lowercase letter (e.g. `<div>`, `<span>`, `<table>`) | Use a layout or content component such as `<Card>`, `<Stack>`, `<DataTable>` |

### Attributes

| Message | Cause | Fix |
|---------|-------|-----|
| `Attribute "<name>" is not allowed. Use the component's variant props instead.` | `className`, `class`, `style`, `dangerouslySetInnerHTML`, or `ref` appears on a JSX element | Use the component's `tone`, `size`, `density`, or `gap` props |

### Banned Identifiers

| Message | Cause | Fix |
|---------|-------|-----|
| `"<name>" is not available inside a view.` | Reference to a banned global: `window`, `document`, `globalThis`, `self`, `parent`, `top`, `fetch`, `XMLHttpRequest`, `WebSocket`, `localStorage`, `sessionStorage`, `indexedDB`, `Worker`, `SharedWorker`, `eval`, `require` | Remove the reference. For data, declare a query and use `useViewQuery`. For periodic UI updates, use `<RelativeTime />` |
| `Function constructor is not allowed inside a view.` | Reference to the `Function` global | Inline the logic |
| `"setTimeout" is not allowed inside a view. For periodic updates, use the <RelativeTime /> component.` | A `setTimeout(...)` call | Replace with `<RelativeTime />` or remove the call |
| `"setInterval" is not allowed inside a view. For periodic updates, use the <RelativeTime /> component.` | A `setInterval(...)` call | Same as above |
| `"new Function" is not allowed inside a view.` | `new Function(...)` constructor call | Inline the logic |
| `"new Worker" is not allowed inside a view.` | `new Worker(...)` constructor call | Workers are not supported in views |
| `Dynamic import is not allowed inside a view.` | `import(...)` expression | Move the import to the top of the file |
| `"import.meta" is not available inside a view.` | `import.meta.*` reference | Remove the reference |

## Shape Errors

These come from `defineView(...)` itself.

| Message | Cause | Fix |
|---------|-------|-----|
| `No defineView(...) call was found in this file` | The file does not call `defineView` | Export `defineView({...})` as the default |
| `defineView must be called with an object literal` | `defineView(someVariable)` instead of an object | Inline the config as an object literal |
| `defineView config is missing required "slug"` | The `slug` field is missing | Add a `slug: "..."` matching `/^[a-z0-9][a-z0-9-]*$/` |
| `defineView config is missing required "name"` | The `name` field is missing | Add a `name: "..."` |
| `defineView config is missing required "queries"` | The `queries` field is missing | Add at least one query: `queries: { rows: { type: "..." } }` |
| `defineView config is missing required "render" function` | The `render` field is missing or not a function | Add `render: () => <Stack>...</Stack>` |
| `queries must be a plain object literal at <file>:<line>` | `queries` is a variable, spread, or computed expression | Inline `queries` as an object literal |
| `queries keys must be plain identifiers or string literals` | A query key uses a computed expression | Use a literal name like `sessions` or `"sessions"` |
| `queries.<name> must be a plain object literal at <file>:<line>` | A query value is not an object literal | Inline the query as `{ type: "...", limit: 100 }` |
| `queries.<name> contains a non-literal value` | A field inside a query is a variable or expression | Use literal values; pass dynamic params through `useViewQuery(name, runtimeParams)` |

## Bundle Errors

| Message | Cause | Fix |
|---------|-------|-----|
| `Failed to parse view source: <message>` | Syntax error before AST analysis | Fix the TSX syntax at the reported location |
| `<esbuild message>` | esbuild bundling failed (unresolved imports, JSX errors) | Imports must resolve to `"struere/view"`; check the reported file and line |

## Size Errors

| Message | Cause | Fix |
|---------|-------|-----|
| `View source exceeds 65536 bytes (got <n> bytes). Split the view or remove unused code.` | Source file is over 64 KB | Split the view into multiple smaller views, or extract repetitive data into the entity layer |
| `Compiled view bundle exceeds 262144 bytes (got <n> bytes). Split the view or remove unused code.` | Bundled output is over 256 KB | Remove unused code paths; large inline data should live in entities |

## Slug and Sync Errors

| Message | Cause | Fix |
|---------|-------|-----|
| `View slug "<slug>" must be lowercase letters, numbers, and dashes only (matching /^[a-z0-9][a-z0-9-]*$/)` | Slug contains invalid characters or starts with `-` | Rename the slug to match the pattern |
| `Duplicate view slug "<slug>"` | Two `.tsx` files declare the same slug | Pick a unique slug per view; the file name does not have to match the slug |
| `View "<slug>" must declare at least one query` | The `queries` object is empty | Add at least one query |

## Reading Error Output

Compile errors print as:

```
✖ views/operations-dashboard.tsx:17:8
  Raw HTML element <div> is not allowed.
  hint: Replace <div> with a layout/content component such as <Card>, <Stack>, <DataTable>, etc.
```

The same errors block `struere dev`, `struere sync`, and `struere deploy`. Fix the file and the next save (in `dev`) or the next invocation (in `sync`/`deploy`) will retry.
