{"record":{"id":"3355963164eea400","repo":"streamich/react-use","slug":"uselocalstorage-key-may-not-be-falsy","errorCode":null,"errorMessage":"useLocalStorage key may not be falsy","messagePattern":"useLocalStorage key may not be falsy","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/useLocalStorage.ts","lineNumber":23,"sourceCode":"  | {\n      raw: true;\n    }\n  | {\n      raw: false;\n      serializer: (value: T) => string;\n      deserializer: (value: string) => T;\n    };\n\nconst useLocalStorage = <T>(\n  key: string,\n  initialValue?: T,\n  options?: parserOptions<T>\n): [T | undefined, Dispatch<SetStateAction<T | undefined>>, () => void] => {\n  if (!isBrowser) {\n    return [initialValue as T, noop, noop];\n  }\n  if (!key) {\n    throw new Error('useLocalStorage key may not be falsy');\n  }\n\n  const deserializer = options\n    ? options.raw\n      ? (value) => value\n      : options.deserializer\n    : JSON.parse;\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  const initializer = useRef((key: string) => {\n    try {\n      const serializer = options ? (options.raw ? String : options.serializer) : JSON.stringify;\n\n      const localStorageValue = localStorage.getItem(key);\n      if (localStorageValue !== null) {\n        return deserializer(localStorageValue);\n      } else {\n        initialValue && localStorage.setItem(key, serializer(initialValue));","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/streamich/react-use/blob/fbe99c6327e6af94df03bc8bd6ecc5e3ff04fbcc/src/useLocalStorage.ts#L5-L41","documentation":"Thrown by useLocalStorage when its `key` argument is falsy. The hook runs an SSR short-circuit first (returns [initialValue, noop, noop] when not in a browser), so this check only executes client-side; once there, any falsy key (empty string '', 0, false, null, undefined, NaN) is rejected because localStorage cannot be keyed by such a value. Passing a non-string key would also fail at the storage API, so the library fails fast with a clear message instead.","triggerScenarios":"Calling useLocalStorage(key, initialValue, options) where key evaluates to a falsy value: an empty string, undefined (e.g. from an unset prop/env), null, 0, or false. Typically the key is derived from a prop, route param, or config that has not resolved yet.","commonSituations":"Key built from an optional prop (id ?? '') producing ''; reading a key from env/config that is undefined in some environments; dynamic keys computed before data loads; passing a numeric id (0 is falsy) instead of a stringified storage key.","solutions":["Provide a stable, non-empty string key: useLocalStorage(`item-${id}`, initialValue) and ensure the interpolated value is defined.","Guard before calling: if (!key) return fallback; else call the hook — or compute key with a guaranteed prefix/default.","If the key depends on async data, render the component using useLocalStorage only after the key is known (conditional rendering), or lift the key to a parent.","Stringify numeric ids and avoid using 0/false as keys."],"exampleFix":"// before\nuseLocalStorage(userId, defaultPrefs);        // userId may be 0 or undefined\nuseLocalStorage(maybeKey, defaultPrefs);       // maybeKey may be '' or undefined\n\n// after\nuseLocalStorage(`user:${userId}`, defaultPrefs);\n// or skip until known:\nif (!maybeKey) return <Fallback/>;\nuseLocalStorage(maybeKey, defaultPrefs);","handlingStrategy":"validation","validationCode":"function useLocalStorageSafe<T>(key: string, initial?: T, opts?: parserOptions<T>) {\n  if (!key || typeof key !== 'string') {\n    throw new Error('useLocalStorage requires a non-empty string key');\n  }\n  return useLocalStorage<T>(key, initial, opts);\n}\n\n// or coerce at the call site:\nconst storageKey = key ? `ns:${key}` : 'ns:default';\nconst [val, setVal] = useLocalStorage(storageKey, initial);","typeGuard":"const isStorageKey = (v: unknown): v is string =>\n  typeof v === 'string' && v.length > 0;\n\nif (isStorageKey(key)) {\n  const [val, setVal] = useLocalStorage(key, initial);\n}\n// else branch: key not ready — render a fallback / skip the hook","tryCatchPattern":"// Hooks cannot be wrapped in try/catch around the call cleanly; instead guard the\n// key before calling. If you must isolate, render the hook behind a gate:\n{hasKey ? <UsesLocalStorage/> : <Fallback/>}","preventionTips":["Always namespace and stringify keys (e.g. `app:user:${id}`) so they are never empty or falsy.","Derive keys only from values that are guaranteed defined (avoid optional props without a default).","When a key depends on async data, gate the component rendering the hook until the key is known.","Never pass 0, false, null, or '' as a key."],"tags":["react","hooks","localstorage","validation","browser"],"backgroundTag":null,"analyzedSha":"fbe99c6327e6af94df03bc8bd6ecc5e3ff04fbcc","analyzedAt":"2026-08-12T19:24:06.802Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}