# Troubleshooting & FAQ

> Common issues and the questions that come up most.

Answers to the issues that come up most. If something here doesn't cover it,
[get in touch](/contact).

## My flag change isn't showing up in my app

This is almost always **poll timing**. Delivery is poll-based: the SDK refreshes
its config every ~10 seconds, and the CDN file is cached with `max-age=10`. A
change you save in the dashboard reaches a running client **within about twenty
seconds**, not instantly.

What to check:

- **Wait one poll interval** (~10s) and retry. The change publishes immediately,
  but clients pick it up on their next poll.
- **Did you click Save?** The dashboard batches edits — nothing publishes until
  you Save (see [Creating & editing flags](/docs/dashboard/flags)).
- **Right environment?** A change in `development` won't affect an app using the
  `production` key. Confirm which key your app uses.

## The connection badge says "Never"

The badge flips to **Connected** the first time any client fetches that
environment's config. If it's stuck on Never:

- **Check the SDK key.** It must be the key for *that* environment, copied
  exactly. A typo means the SDK is fetching a path that doesn't exist (a 404), so
  no fetch is recorded.
- **Did the client actually start?** Make sure your code creates the client and
  the process ran. In the browser, confirm the page that initialises the SDK
  loaded.
- **Give it a few seconds.** The first fetch is recorded server-side on the read
  path; allow a moment after your app starts.

## `enabled()` always returns false

- **The flag may not exist** under that key, or no config has loaded yet — both
  return the safe `false`. Double-check the key (it's `lowercase_snake_case`) and
  that the client is [`ready`](/docs/sdk/python).
- **The flag may be off** in that environment, or the user doesn't match its rules
  and falls outside the rollout. Use the **Playground** to see exactly how it
  evaluates for a given user.

## `get_value()` returns my default, not the configured value

The SDK returns your `default` when the flag is **absent** or **no config has
loaded**. Confirm the key exists, the client is ready, and — for non-boolean
flags — that you've set an `enabled_value` (without one, matched users fall back
to `default_value`). See [Flags & flag types](/docs/concepts/flags).

## A user gets a different rollout result than I expected

Rollout bucketing is **deterministic**: `sha256("{user_id}:{flag_key}") % 100`.

- The **same user always lands in the same bucket** for a flag, so the result is
  stable across requests — if it looks "wrong", it's consistently wrong, which
  usually means that user simply isn't in the cohort yet.
- **Rules win over rollout.** A user who matches a targeting rule gets the enabled
  value regardless of the percentage.
- **No `user_id` means no bucketing.** Without an `id`, a flag below 100% falls
  back to the default. Pass a `user_id`.

See [Percentage rollouts](/docs/concepts/rollouts).

## Does the SDK add network latency to my flag checks?

No. The SDK fetches the config in the background and evaluates **locally**, in
memory. `enabled()` / `getValue()` make no network call and resolve in
sub-millisecond time. The only network activity is the periodic background poll.

## What happens if Switchbox (or the CDN) is down?

Your flags keep working on the **last config the SDK fetched**. If a client has
never successfully fetched a config, `enabled()` returns `false` and `getValue()`
returns your default — never an exception. See
[How it works](/docs/concepts/how-it-works).

## Do the SDKs pull in other dependencies?

No. Every SDK has **zero runtime dependencies** — the Python SDK uses only the
standard library; the JavaScript SDKs use only `fetch` and Web Crypto.
`pip install switchbox-flags` and `npm install switchbox-js` add nothing else.

## Next

- [Evaluation order](/docs/reference/evaluation-order) — the definitive
  resolution logic.
- [Contact](/contact) — still stuck? Reach out.
