# Known Limitations

This page lists behaviors in the v1.0.0 source that affect read fallback and recovery. Each one has been reproduced and comes with a workaround.

## Read and Recovery

| Behavior | Impact | Workaround |
|---|---|---|
| When `{DBPath}/{DB}` is missing at startup, recovery returns early while walking the directory (`sync.go:64-66`) | `isHealth` is never set to `true` and no health check runs; the instance stays in local mode for good and never touches Redis, while the log still prints `Starting normal mode` | Call `os.MkdirAll(filepath.Join(DBPath, strconv.Itoa(DB)), 0755)` before `New` |
| `Set` writes `Data` itself to Redis, but `Get` expects a `Cache` JSON value (`set.go:36-44`, `get.go:47-51`) | Every memory miss (another instance, after a restart) fails to parse and switches to fallback once retries are exhausted | Read and write each key from the same long-lived instance, or make sure the key is in memory before reading |
| `redis.Nil` (key missing) counts as a failure (`get.go:41-50`) | Reading one missing key switches the instance to fallback until the next successful health check | Lower `TimeToCheck` to shorten the time spent in fallback |
| Recovery deletes local files whether or not the pipeline succeeded (`sync.go:84-87`) | Data that failed to resync survives only in memory and is lost when the process exits | None; the source must check the `Exec` result |
| `ttl = 0` entries are not in the recovery batch (`sync.go:115-118`) | They return to Redis only after being read once ([Read-Repair](/read-repair)) | Set a TTL on keys that must persist |
| Normal mode reads memory first without asking Redis | External changes or deletes in Redis are invisible to this instance until the memory entry expires | Use short TTLs for keys that need to stay consistent |

## Writes and Lifecycle

| Behavior | Impact | Workaround |
|---|---|---|
| A nil `Config.Redis` panics | `New` panics when the ping succeeds | Always pass `&redisFallback.Redis{}` |
| A `nil` `value` in `Set` panics (`set.go:19`) | `reflect.TypeOf(nil).String()` | Check for nil before calling |
| TTLs under one second truncate to 0 | Equivalent to no expiry | Use a TTL of at least one second |
| `Close` does not flush the write queue | Fallback writes from the last `TimeToWrite` never reach disk | Wait longer than `TimeToWrite` before `Close` |
| `Close` does not stop the writer goroutine or the 30-second sweep ticker | Repeatedly creating and closing instances accumulates goroutines | Create one instance per process |
| The memory cache has no size limit | Entries are removed only on expiry; `ttl = 0` entries are never removed | Set a TTL on every key |
| `Del` during fallback is not replayed to Redis on recovery | The deleted key stays in Redis until it expires | `Del` the key again after recovery |
| `EmailConfig` never sends mail | The setting has no effect | — |

## Error Messages

`Get` returns only `Not found` and `Failed to parse`, so the error cannot distinguish "missing", "expired", and "Redis down and nothing local". To learn the current mode, read the log (see [Getting Started](/getting-started#checking-the-current-mode)).
