{"record":{"id":"5dfb7f539a01dc4a","repo":"benbjohnson/litestream","slug":"litestream-hydration-progress-is-read-only","errorCode":null,"errorMessage":"litestream_hydration_progress is read-only","messagePattern":"litestream_hydration_progress is read-only","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":2482,"sourceCode":"\t\tif strings.EqualFold(*pragmaValue, \"latest\") {\n\t\t\tif err := f.ResetTime(context.Background()); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tt, err := parseTimeValue(*pragmaValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := f.SetTargetTime(context.Background(), t); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, nil\n\n\tcase \"litestream_hydration_progress\":\n\t\tif pragmaValue != nil {\n\t\t\treturn nil, fmt.Errorf(\"litestream_hydration_progress is read-only\")\n\t\t}\n\t\tif f.hydrator == nil {\n\t\t\tresult := \"0\"\n\t\t\treturn &result, nil\n\t\t}\n\t\tpct := f.hydrator.Status().Pct() * 100\n\t\tresult := strconv.FormatFloat(pct, 'f', 1, 64)\n\t\treturn &result, nil\n\n\tcase \"litestream_hydration_file\":\n\t\tif pragmaValue != nil {\n\t\t\treturn nil, fmt.Errorf(\"litestream_hydration_file is read-only\")\n\t\t}\n\t\tresult := f.hydrationPath\n\t\treturn &result, nil\n\n\tcase \"litestream_write_enabled\":\n\t\tif pragmaValue == nil {","sourceCodeStart":2464,"sourceCodeEnd":2500,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L2464-L2500","documentation":"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).","triggerScenarios":"Executing `PRAGMA litestream_hydration_progress = <value>` on a connection backed by the litestream VFS. The non-nil pragmaValue triggers the read-only guard.","commonSituations":"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.","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"],"exampleFix":"// before\nPRAGMA litestream_hydration_progress = 100;  -- force-complete hydration\n// after\nPRAGMA litestream_hydration_progress;  -- read current % (e.g. '42.5')\n-- poll until '100.0' to know hydration finished","handlingStrategy":"validation","validationCode":"// Reject assignment form before executing\nif strings.Contains(strings.ToLower(stmt), \"litestream_hydration_progress=\") ||\n   strings.Contains(strings.ToLower(stmt), \"litestream_hydration_progress =\") {\n    return errors.New(\"litestream_hydration_progress is read-only; use the read form PRAGMA litestream_hydration_progress;\")\n}","typeGuard":null,"tryCatchPattern":"_, err := db.Exec(\"PRAGMA litestream_hydration_progress = ?\", v)\nif err != nil && strings.Contains(err.Error(), \"litestream_hydration_progress is read-only\") {\n    // fall back to polling the read form\n    row := db.QueryRow(\"PRAGMA litestream_hydration_progress\")\n    var pct string\n    _ = row.Scan(&pct)\n}","preventionTips":["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"],"tags":["go","sqlite","pragma","read-only","hydration"],"backgroundTag":"read-only-pragma-assignment","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}