# Comments limits and errors

## Handle errors

The [runtime methods](https://vitehub.dev/docs/comments/server-api#runtime-methods) return `[error, data]`. When `error` is set, `error.code` names the failure, `error.why` tells what went wrong, `error.fix` tells what to do, and `error.docs` links to the code on this page.

```ts [server/api/threads/[id].get.ts]
import { createError, defineEventHandler, getRouterParam } from 'h3'
import { comments } from '../../comments'

export default defineEventHandler(async (event) => {
  const [error, thread] = await comments.get(getRouterParam(event, 'id')!)
  if (error?.code === 'COMMENTS_NOT_FOUND') throw createError({ status: 404, message: error.why })
  if (error) throw error
  return thread
})
```

The HTTP routes answer with the same error object as `{ error }`, and an HTTP status for each code. See [HTTP routes](https://vitehub.dev/docs/comments/server-api#http-routes). The overlay shows `why` and `fix` in a message.

Build errors throw when Vite reads the config. When the build cannot choose the Database for the Comments tables, it fails with [`DATABASE_INVALID_CONTRIBUTION_TARGET`](https://vitehub.dev/docs/database/limits-and-errors#database_invalid_contribution_target). See [Choose the Database](https://vitehub.dev/docs/comments/configure#choose-the-database).

## Limits

| Limit | Value |
| --- | --- |
| Comment body | 1 to 4,000 characters of plain text, after trimming |
| Mentions in one comment | 20 |
| `@` suggestions | 20 |
| Threads in one `list()` call | 200 by default, 500 at most |
| Threads in the Console section | The 500 with the newest activity |
| Page path | 1,024 characters, starting with `/` |
| Guest name | 64 characters |
| Content field address | 512 characters |
| Edited field value | 20,000 characters |
| Thread refresh without presence | On tab focus, and every 30 seconds while the tab is visible |
| Cursor updates | One every 80 ms for each person |
| Presence rooms with `authority: 'memory'` | One process. See [Realtime limits](https://vitehub.dev/docs/realtime/limits-and-errors#limits). |

## Runtime errors

### COMMENTS_NOT_INSTALLED

The Comments runtime has no Database yet. ViteHub installs it from `server/comments.ts` when the server starts. Call the method from a server route or a Nitro plugin, not at import time. When the server log shows `Comments has no Database`, turn on a Database with `vitehub({ database: true })`, or set `defineComments({ database })` to a Database name.

### COMMENTS_NOT_FOUND

No thread or comment has the id. A deleted thread does not come back. List the threads with `comments.list()` and use one of their ids. The HTTP API also returns this code, with status `404`, for a route that does not exist.

### COMMENTS_INVALID_INPUT

The input of `create()` or `reply()`, or the body of an API request, is not valid. `why` names the first issue, such as `body: The comment is empty.` Send a page path that starts with `/`, an anchor from the overlay, and a body of 1 to 4,000 characters, with at most 20 mentions.

### COMMENTS_FORBIDDEN

The `authorize` policy of `defineComments()` denied the action for this user. `why` names the action: `read`, `comment`, or `resolve`. Sign in as a user that the policy allows, or change `authorize` in `server/comments.ts`. See [Decide who can comment](https://vitehub.dev/docs/comments/configure#decide-who-can-comment).

The API also returns this code for a `POST` or `DELETE` from another origin. Behind a proxy that ends TLS, set `X-Forwarded-Proto` and `X-Forwarded-Host`. See [Proxies that end TLS](https://vitehub.dev/docs/comments/hosts#proxies-that-end-tls).

### COMMENTS_RESOLVED

The thread is resolved, so it takes no new replies. Reopen it with `comments.reopen(id)`, or with the reopen button on the page, then reply.

## Content edit errors

### COMMENTS_CONTENT_MISSING

Edits in place need Content, and the app has no `server/content.ts` with document collections. Define collections with `defineContent()` in `server/content.ts`, mark rendered fields with `contentField()`, and restart the dev server.

### COMMENTS_FIELD_INVALID

The `data-content-field` value is not a Content field address, or its collection or document does not exist, or the document has no draft yet. Write the attribute with `contentField(collection, id, field)` from `vite-hub/content/client`, so the address matches a collection of `server/content.ts`. A singleton has no document until its first save. Save it once in the Console.

### COMMENTS_FIELD_NOT_EDITABLE

The draft value of the field is not a string, so the page cannot edit it as text. Edit the field in the Console Content editor.

### COMMENTS_FIELD_FORBIDDEN

`content.can()` denied `write` on the document for this user. Sign in as a user that the `authorize` policy of `defineContent()` lets write the collection. See [Content access](https://vitehub.dev/docs/content/configure#access).

### COMMENTS_FIELD_CONFLICT

The document changed after the page read it, for example in the Console or in another tab. Open the field again to read the current draft, then repeat the edit.

### COMMENTS_FIELD_LOCKED

Another person holds the edit lease of this document in the Console. `why` names them. Wait until they close the document, or edit it together with them in the Console. See [Editing together](https://vitehub.dev/docs/content/editing-together).
