benbjohnson/litestream · error
litestream_hydration_progress is read-only
Error message
litestream_hydration_progress is read-only
What it means
The litestream_hydration_progress PRAGMA is read-only: FileControl() in vfs.go returns this error when pragmaValue is non-nil (assignment form). Reading it returns the hydrator's completion percentage (0 when no hydrator is attached, otherwise hydrator.Status().Pct()*100 formatted to one decimal).
Source
Thrown at vfs.go:2482
if strings.EqualFold(*pragmaValue, "latest") {
if err := f.ResetTime(context.Background()); err != nil {
return nil, err
}
return nil, nil
}
t, err := parseTimeValue(*pragmaValue)
if err != nil {
return nil, err
}
if err := f.SetTargetTime(context.Background(), t); err != nil {
return nil, err
}
return nil, nil
case "litestream_hydration_progress":
if pragmaValue != nil {
return nil, fmt.Errorf("litestream_hydration_progress is read-only")
}
if f.hydrator == nil {
result := "0"
return &result, nil
}
pct := f.hydrator.Status().Pct() * 100
result := strconv.FormatFloat(pct, 'f', 1, 64)
return &result, nil
case "litestream_hydration_file":
if pragmaValue != nil {
return nil, fmt.Errorf("litestream_hydration_file is read-only")
}
result := f.hydrationPath
return &result, nil
case "litestream_write_enabled":
if pragmaValue == nil {View on GitHub (pinned to 4ed7a308f6)
Solutions
- Remove the assignment; use the read form `PRAGMA litestream_hydration_progress;`
- Poll the read form until it reports 100.0 to wait for hydration completion
- If hydration appears stuck, inspect replica connectivity/storage rather than attempting to write progress
- Catch the error and explain progress is computed from hydrator status
Example fix
// before PRAGMA litestream_hydration_progress = 100; -- force-complete hydration // after PRAGMA litestream_hydration_progress; -- read current % (e.g. '42.5') -- poll until '100.0' to know hydration finished
Defensive patterns
Strategy: validation
Validate before calling
// Reject assignment form before executing
if strings.Contains(strings.ToLower(stmt), "litestream_hydration_progress=") ||
strings.Contains(strings.ToLower(stmt), "litestream_hydration_progress =") {
return errors.New("litestream_hydration_progress is read-only; use the read form PRAGMA litestream_hydration_progress;")
} Try / catch
_, err := db.Exec("PRAGMA litestream_hydration_progress = ?", v)
if err != nil && strings.Contains(err.Error(), "litestream_hydration_progress is read-only") {
// fall back to polling the read form
row := db.QueryRow("PRAGMA litestream_hydration_progress")
var pct string
_ = row.Scan(&pct)
} Prevention
- Only query litestream_hydration_progress; it reflects hydrator status
- Poll the read form until it returns '100.0' instead of trying to set completion
- Remember '0' means no hydrator is attached — check hydration setup if stuck at 0
- Block write-forms of litestream_* pragmas in application DB layers
When it happens
Trigger: Executing `PRAGMA litestream_hydration_progress = <value>` on a connection backed by the litestream VFS. The non-nil pragmaValue triggers the read-only guard.
Common situations: Developers try to 'set' hydration progress to mark hydration complete or reset it. Progress is a computed status of the internal hydrator; it can only be observed, and it advances as the hydrator downloads/applies LTX data.
Related errors
- litestream_txid is read-only
- litestream_lag is read-only
- could not parse time: %s
- litestream_hydration_file is read-only
- set page size: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/5dfb7f539a01dc4a.
Report an issue: GitHub.