Data limits and errors
The numbers to design for, and every error the data service can send, with what it means and how to fix it.
The data service is small on purpose. Knowing its edges early saves a late-night surprise.
Limits
Calls per minute429 rate_limited with a retry-after header and x-ratelimit-* headers.Rows per readtake, you get 100. A bigger take is quietly cut to 1000. The same caps apply to $app.Rows from $app.sqlTime per query504 query_timeout. A raw SQL statement answers 400 sql_failed. The statement is not cancelled on the database side, so keep queries light.Queries at once429 too_many_queries. Other projects are not affected.Request size400 invalid_request with a message that says the body is not valid JSON. The message is misleading. The body is simply too big.WritersDatabasesData key lifeVisitor contextSDK retriesAfter a deploy or rollbackmember_of) show up within about 3 seconds.What is not limited
The platform does not set a per-project cap on storage size or on rows read and written today. Do not read that as unlimited: a limit may arrive, and the database provider's own plan sits underneath. There is also no documented maximum number of tables, columns, migration files or rows in a createMany.
Speed
Do not plan around exact figures. A create takes several steps inside the database, so it is slower than a read, and createMany is one call instead of many. A caller far from the platform feels each round trip. Write throughput for one project is modest, and it has not been measured well enough to promise a number.
Designing for the limits
- Page with
takeandskipinstead of asking for everything. - Batch with
createMany, in pieces under 1 MB. - Count with
count, not by reading all rows. - Do heavy totals once, in a job through
$app.sql, and store the result in a table. - If you see
429, wait and try again. Do not loop at full speed.
Errors
A platform-made error looks like this:
{ "error": { "code": "database_not_ready", "message": "This project has no managed database yet.", "how_to_fix": "Set \"bindings\": {\"data\": {\"managed\": true}} in the manifest, add migrations, and deploy." } }
In the SDK these arrive as a PlatformError with status, code, message and howToFix. The next table lists each code, with its HTTP status.
invalid_token401PLATFORM_TOKEN as X-Platform-Binding-Token.binding_not_declared403data binding. Add data under bindings in cohostly.json and deploy.rate_limited429retry-after time.database_not_ready409"bindings": { "data": { "managed": true } }, add migrations, and deploy. This also happens under cohostly dev if the project has never been deployed.invalid_context401X-Platform-Context header of the request your app received, unchanged.context_for_another_app403context_unavailable503data_api_not_allowed403missing_scope403data:read or data:write for this call. Make a key with the scope the call needs.raw_sql_not_allowed403$app.sql.sql_not_allowed400sql_failed400not_available400not_found404/data/api/model/<table>/<operation> with a table that exists.query_timeout504too_many_queries429invalid_request400Errors from the rules
Some errors come from the row rules and have no code or how_to_fix of their own:
- A write refused by a rule:
403, withrejectedByPolicy: truein the body. In the SDK, checke.status === 403 && e.details?.rejectedByPolicy. The caller is not allowed to do that to that row. Check who is calling and which lines the table has. Do not retry it. - A wrong HTTP method, an unknown table, or a badly shaped query:
400. If you call by hand, use the method and address in the SDK reference.
Things that look like errors but are not
- An empty list and no error. Reads that a rule hides return fewer rows, not a refusal. A table with no rule returns
[]to visitors, and refuses their writes with403. - A
countof 0 fromupdateManyordeleteMany. No row matched, or none was yours.
Deploy errors
These stop a deploy before anything is built. Every one is explained where it happens.
Migration <name> could not be applied to an empty database422The migration <name> was already applied and has been edited since.409The migration <name> failed on the database422Table "<t>": the policy "<text>" ...422The table name "<t>" cannot be used.422The migrations create no tables...422The project's database could not be prepared.502The checks that run before the build reply with the body { "error": "Your data could not be set up", "details": "<message>" }. The 502 has its own sentence.
If you have a problem that is not here, see troubleshooting.