# `type.batch_from_invalid`

A batch's `from:` is something other than a call of a named query that gives a `Page`, such as a query that gives a `List`.

Area 12, [Background work](/docs/jobs-and-events.md); not declinable; the next step is usually the agent's.

## Why Jadpo refuses it

A batch, such as `batches.each` or a file's write helper, walks `from:`
a page at a time in the background, after the action that starts it
commits. The run keeps the cursor of the next page, so a crash or a
deploy carries on where it stopped. A query that gives a `List`, or a page already read, has no
cursor to keep, so the run couldn't keep its place.

## What it looks like

main.jadpo, beside a `stock.jadpo` that declares `Item`, a paged query
`items` and the action `mark_seen`:


```jadpo
query first_items() -> List<Item> {
    from: Item
    order: [Item.code asc]
    limit: 10
}

action sweep_shelf() -> BatchRun {
    return batches.each(from: first_items(), each: item -> mark_seen(item))
}
```

```text
error: `batches.each`'s `from:` isn't a call of a named query giving a `Page`
 --> main.jadpo:8:31
  |
8 |     return batches.each(from: first_items(), each: item -> mark_seen(item))
  |                               ^^^^^^^^^^^^^ gives `List<Item>`
  reason: A run walks `from:` a page at a time, after the action that starts it commits: it calls a named query that gives a `Page<T>`, and each item is a `T`; the query's arguments are worked out now and saved with the run.
  next: Write `batches.each(from: <query>(...), ...)`, with a query whose result is `Page<T>` (agent)
  rule: type.batch_from_invalid
  help: https://jadpo.dev/docs/errors/type.batch_from_invalid

check failed: 1 error, 2 files
```

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

## How to fix it

**If a query giving a `Page` of the items already exists**, give the
action that query's page settings and call it in `from:`. In
`main.jadpo`, which no longer needs `first_items`:

```jadpo
action sweep_shelf(page: ItemPage) -> BatchRun {
    return batches.each(from: items(page), each: item -> mark_seen(item))
}
```



The run now reads `Item`s in pages of the size `page.page_size` gives, 25
by default, and calls `mark_seen` for each. It orders them by `id`, which
no update changes, so each item is seen exactly once.

When there is only a list's query, make it give a `Page` instead: an
`order:` it can page through and a `page:` with its size and cursor, in
place of `limit:`. That is the shape of `items` in `stock.jadpo`.

## Related

- [Walking records or a provider's list: `batches.each`](/docs/batches-work-over-many-items.md#walking-records-or-a-providers-list-batcheseach)
- [A batch is a page](/docs/how-a-run-is-kept.md#a-batch-is-a-page)
- [Named queries](/docs/named-queries.md)
- [Order and pages](/docs/order-and-pages.md)
