Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 5 Nov 2026. What's built · Install 0.3.0
jadpo
ReferenceErrors

ErrorsHTTP · rule

route.run_kind

On this page

A GET route runs an action that isn't read-only, or a route of another method runs a query.

Area 7, HTTP; not declinable; the next step is usually the agent's.

Why Jadpo refuses it

HTTP promises that a GET only reads, so a browser, a cache or a client library may send one again without asking. Jadpo keeps that promise by what a route runs. A query can only read, so a GET can run one. An action can write, so a GET runs one only when the compiler can prove it writes nothing, emits nothing and makes no changing call, itself and through every action it calls. POST, PUT, PATCH and DELETE run an action, which owns the writes and the transaction, and never a query.

A GET running an action that changes something could change it again each time it is repeated, and nothing can show whether you meant the route to read or to write. The message names what the action does and where, following the calls, so you can see which it is.

What it looks like

Here the action adds a note, so it can't answer a GET:

main.jadpo:

example
type Memo = Text {    max_length: 200}type AddMemo = Input {    text: Memo}type MemoView = Output {    text: Memo}entity Note {    id: Uuid    text: Memo    policy: {        create: [Access.public]        read: [Access.public]    }}action add_memo(input: AddMemo) -> MemoView {    var note: Note = Note.create {        set: {            text: input.text        }    }    return MemoView {        text: note.text    }}routes Memos {    prefix: /memos    GET / {        authentication: RouteAuthentication.none        input: AddMemo        output: MemoView        run: add_memo(input)    }}
jadpo checkcheck failed: 1 error, 1 file

error GET /memos runs action add_memo, which writes with Note.create

--> main.jadpo:41:14

   |24 |     var note: Note = Note.create {   |                      ----------- here41 |         run: add_memo(input)   |              ^^^^^^^^ not read-only
reason
A GET is safe to repeat, so it runs a named query, or an action the graph proves writes nothing, emits nothing and makes no changing call; add_memo writes with Note.create.
next
Answer /memos with another method, or leave Note.create out of what add_memo does (agent)
rule
route.run_kind
help
https://jadpo.dev/docs/errors/route.run_kind

(agent) at the end of the next: line means your coding agent can make the fix itself.

How to fix it

The question is whether the route changes anything.

If the route adds or changes something, answer it with another method, here POST, which reads its input from the JSON body:

example
    POST / {        authentication: RouteAuthentication.none        input: AddMemo        output: MemoView        run: add_memo(input)    }

POST /memos runs add_memo, and a client sends the memo as JSON.

If the route only reads, run a query that reads what it shows, or leave what changes something out of the action. Here the memos are stored as Note records, and the route lists them:

example
query recent_notes() -> List<MemoView> {    from: Note    order: [Note.text asc]    limit: 50}
example
    GET / {        output: List<MemoView>        run: recent_notes()    }

GET /memos answers with up to 50 notes and never writes, so repeating it is safe. A signed-in caller sees the notes Note's read: lets them read.

An action that works something out can stay on the GET, once it stops doing what changes something. An action like this one, which reads and calculates, has nothing to refuse:

example
action check_memo(input: MemoInput) fails TooShort -> MemoView {    if (text.length(input.text) < 3) {        reject TooShort {}    }    return MemoView {        text: input.text    }}

GET /memos now answers with the memo, or 422 too_short, and repeating it changes nothing.

Markdown for agents: /docs/errors/route.run_kind.md.Built from Jadpo main at aee2e8f.