Known Limitations
Features that are designed but not yet fully implemented, and constraints of the current implementation.
What you'll learn: What to expect from the current Grove release and what's coming next.
Area 2: Workflows
Workflow orchestration (Area 2) is designed and parsed but the runtime implementation is in progress:
| Feature | Status |
|---|---|
| Workflow declarations | Parsed and checked |
| Activity declarations | Parsed and checked |
| Service declarations | Parsed and checked |
| Route declarations | Parsed and checked |
| Query declarations | Parsed and checked |
| Trigger declarations | Parsed and checked |
| Schedule declarations | Parsed and checked |
| Webhook declarations | Parsed and checked |
| In-process orchestrator | In development |
| Temporal backend | In development |
You can write and type-check workflow code today. Runtime execution is being implemented.
Agent System
The agent system is in preview:
| Feature | Status |
|---|---|
| Agent declarations | Design finalized |
| Tool declarations | Design finalized |
| MCP server | Design finalized |
| Agent runtime | In development |
| Prompt evaluation | In development |
Temporal Integration
| Feature | Status |
|---|---|
| Bridge architecture | Designed |
| Activity registration | In development |
| Signal/cancel/await | Not yet implemented |
| SDK interop | Not yet implemented |
Runtime Limits
Event payload size
Individual event payloads are capped at 256 KiB. The runtime enforces this on the write path; oversized events return HTTP 413 Payload Too Large with code Z4004 (see Error Reference).
The ceiling is chosen to fit comfortably under the smallest downstream delivery mechanism Grove targets (SQS/SNS/Lambda-async all accept 256 KiB body payloads) while leaving margin inside the 6 MiB TiDB transaction budget for the surrounding commit.
When you hit the limit. Store the bulk payload in blob/object storage (S3, R2, GCS) and put only the reference (URL, key, ETag) in the event. The runtime offers the File type for records that need large attachments — see File Uploads. For event-level attachments, include a URL field in the event and upload separately.
Language Limitations
| Limitation | Details |
|---|---|
| No block comments | Only // line comments are supported |
| No mutable variables | All let bindings are immutable |
| For loop restrictions | Only in action apply blocks, max 3 levels deep |
| No nested type declarations | Types must be declared at module top level |
| Single record per module | Each module can have at most one record block |
| No generic functions | Functions cannot have type parameters |
| No recursive types | Type declarations cannot reference themselves |
Runtime Gotchas
These issues compile successfully but cause unexpected behavior at runtime:
| Issue | Symptom | Workaround |
|---|---|---|
?? null coalesce | Compiles but fails at runtime with "unknown function 'coalesce'" | Use sentinel defaults with if conditionals instead |
| State machine field co-declaration | state status { ... } in a record requires a matching field declaration status: Status = Status.draft | Always declare both the field with its default and the state machine |
| Duration literals in assertions | assert record.prep_time == 2m fails even when the value matches | Use the string form: assert record.prep_time == "2m" |
| Events must set state field explicitly | Emitting a state-transition event like published without a status field in the event doesn't update the status | Add status: Status = Status.published with a default value to the event declaration |
Null Coalesce Workaround
Instead of:
// Does NOT work at runtime:
let name = input.name ?? "default"
Use:
// Works:
if input.name != null {
let name = input.name
} else {
let name = "default"
}
State Machine Co-declaration
The state block and the field it controls must both be declared:
record {
kind "post"
status: ArticleStatus = ArticleStatus.draft // Required field declaration
state status { // State machine references the field
ArticleStatus.draft -> ArticleStatus.published on published
}
}
Event Status Field
State-transition events must explicitly include the status field with a default:
event published {
status: ArticleStatus = ArticleStatus.published // Required for state transition
}
Database Backends
| Backend | Status |
|---|---|
| SQLite | Implemented |
| PostgreSQL | Implemented |
| MySQL | Implemented |
| TiDB | Implemented |
| DynamoDB | Not planned |
| MongoDB | Not planned |
See Also
- Error Reference -- All error codes
- FAQ -- Frequently asked questions