benbjohnson/litestream · error
unsupported file control op: %d
Error message
unsupported file control op: %d
What it means
VFSFile.FileControl() in vfs.go was invoked with a file-control opcode other than SQLITE_FCNTL_PRAGMA (14). FileControl in this VFS only implements PRAGMA dispatch; any other xFileControl op (e.g. other SQLITE_FCNTL_* codes SQLite probes for) is rejected with this error instead of returning a graceful not-supported signal.
Source
Thrown at vfs.go:2429
cfg := &dateparser.Configuration{
CurrentTime: time.Now().UTC(),
}
result, err := dateparser.Parse(cfg, value)
if err != nil {
return time.Time{}, fmt.Errorf("invalid timestamp (expected RFC3339 or relative time like '5 minutes ago'): %s", value)
}
if result.Time.IsZero() {
return time.Time{}, fmt.Errorf("could not parse time: %s", value)
}
return result.Time.UTC(), nil
}
// FileControl handles file control operations, specifically PRAGMA commands for time travel.
func (f *VFSFile) FileControl(op int, pragmaName string, pragmaValue *string) (*string, error) {
const SQLITE_FCNTL_PRAGMA = 14
if op != SQLITE_FCNTL_PRAGMA {
return nil, fmt.Errorf("unsupported file control op: %d", op)
}
name := strings.ToLower(pragmaName)
f.logger.Debug("file control", "pragma", name, "value", pragmaValue)
switch name {
case "litestream_txid":
if pragmaValue != nil {
return nil, fmt.Errorf("litestream_txid is read-only")
}
txid := f.Pos().TXID
result := txid.String()
return &result, nil
case "litestream_lag":
if pragmaValue != nil {
return nil, fmt.Errorf("litestream_lag is read-only")View on GitHub (pinned to 4ed7a308f6)
Solutions
- Confirm which opcode value appears in the message; only 14 (SQLITE_FCNTL_PRAGMA) is supported
- If it comes from SQLite's internal probing, treat it as benign/not-applicable and ensure the caller handles the error as 'not supported'
- Route PRAGMA operations via PRAGMA statements so they arrive as op 14
- If a needed op is legitimately required (e.g. size hint or persist-WAL), extend FileControl to handle or gracefully ignore that opcode
- Check the litestream VFS version for added opcode support
Example fix
// before
result, err := file.Control(SOME_FCNTL_OP, "", nil)
if err != nil { panic(err) }
// after
result, err := file.Control(SOME_FCNTL_OP, "", nil)
if err != nil {
if strings.Contains(err.Error(), "unsupported file control op") {
return nil // op not supported by this VFS; proceed without it
}
return err
}
// or use PRAGMA instead:
db.Exec("PRAGMA litestream_txid") Defensive patterns
Strategy: try-catch
Validate before calling
// Only issue op 14 (SQLITE_FCNTL_PRAGMA) through this VFS; prefer PRAGMA statements:
const SQLITE_FCNTL_PRAGMA = 14
if op != SQLITE_FCNTL_PRAGMA {
// skip: this VFS only supports PRAGMA file controls
return
} Type guard
func isPragmaFileControl(op int) bool { return op == 14 } Try / catch
_, err := file.FileControl(op, name, val)
if err != nil {
var unsupported bool
if strings.Contains(err.Error(), "unsupported file control op") {
unsupported = true // treat as not-implemented, degrade gracefully
}
_ = unsupported
} Prevention
- Use PRAGMA statements (they map to op 14) instead of raw xFileControl calls
- Treat this error as 'feature not supported' and no-op, matching SQLite conventions
- Keep the SQLite driver/library version compatible with the litestream VFS build
- When adding VFS features, extend FileControl with explicit opcode handling
When it happens
Trigger: SQLite core or an extension issues an xFileControl call with an opcode other than 14 against the litestream VFS file — typically during database open/feature probing, WAL mode negotiation, or when an extension requests an fcntl the VFS does not implement.
Common situations: Happens during normal SQLite operation when the core probes for optional file-control features; also seen when drivers or tools issue non-PRAGMA file controls directly. Developers debugging 'unsupported file control op' usually assumed all fcntl ops were handled or that the error indicates corruption — it does not.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- cannot delete vfs file
- could not parse time: %s
- FileControlPersistWAL: %w
- snapshot wal read exceeded bound: max offset %d > end offset
- write snapshot ltx: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/fda95b201de3bd2f.
Report an issue: GitHub.