Skip to content
Back to skills

Server Function Validation

ASecurity

A server function checks every argument against a valibot schema from src/server/validate.ts before it acts, because the parameter types are gone by the time a call arrives. Applies whenever adding a 'use server' function or giving an existing one something new to read.

  • 5 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 20, 2026
databasesgosecurity

Security analysis

A100/100

Scanned September 28, 2026

npx -y skills add lxsmnsyc/overwander --skill server-function-validation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Server Function Validation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Server Function Validation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/lxsmnsyc-server-function-validation/badge)](https://www.skillsdirectory.com/skills/lxsmnsyc-server-function-validation)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: server-function-validation
description: A server function checks every argument against a valibot schema from src/server/validate.ts before it acts, because the parameter types are gone by the time a call arrives. Applies whenever adding a 'use server' function or giving an existing one something new to read.
---

# Server functions check what they are sent

A `'use server'` function is an HTTP endpoint. Its parameter list is erased at build time, so the arguments that reach it are whatever the caller put in the request body, not what the signature says. The modules under `src/server/` then act on those arguments over the table-owner connection, which row-level security does not bind.

Every argument is therefore checked first, at the top of the body:

```ts
async function useMintOnServer(token: string, catchId: string, item: Items): Promise<Natures | null> {
  'use server';
  check(TOKEN, token);
  check(ID, catchId);
  check(GAME_ID, item);
  return useMintOnServerSide(await requireUid(token), catchId, item);
}
```

`check` and the schemas both come from [`src/server/validate.ts`](../../../src/server/validate.ts). A failing check throws, which is what a malformed call deserves.

## The rules

- **One line per parameter**, in the order the parameters are declared, before anything else in the body. `requireUid` comes after them, or `requireReader` for a read (see `server-reads`).
- **Reuse a schema.** `ID` for a row key, `GAME_ID` for a registry id, `CHUNK_COORDINATE` and `CELL` for where somebody says they are, `OFFSET` and `LOCALE` for the caller's zone, `UID` for an account. A new shape gets a new exported schema in `validate.ts` rather than an inline one at the call site.
- **Bound every list.** An array schema carries a `maxLength`, since an unbounded list is a request to do unbounded work.
- **Check the shape, not the rule.** A schema says an argument is a chunk inside the world or a text id of a sane length. Whether the player owns that catch, can afford it or may reach that landmark stays in `src/server/`.
- **Nothing is coerced.** `check` hands the argument back as it arrived, so the `as*` normalizers further in still see what the caller actually sent.

## Why it is not the transform's job

Adding a check never changes a function's parameters, so it does not move anything: see `server-function-order` for why that matters.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…