> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.clubedge.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Diagnose and fix common feature flag issues: flag not found, stale values, auth errors, and SDK evaluation caveats.

<TableOfContents />

## Quick diagnosis checklist

Before diving into specific symptoms, run through these checks:

1. **Is the SDK initialized?** — `await client.initialize()` must complete before any `isEnabled()` call.
2. **Does the flag exist?** — Check the Admin API: `GET /flags` with the flag key.
3. **Is the flag enabled for the environment?** — `GET /flags/{id}/environments/{envId}` and check `isEnabled`.
4. **Is the environment active?** — A revoked environment rejects all evaluation requests with `401`.
5. **Does the SDK key match the environment?** — The key is environment-scoped; a key from staging won't resolve production flags.
6. **Is the flag archived?** — Archived flags always return `false`.

## Symptom: `isEnabled()` throws `FLAG_NOT_FOUND`

| Likely cause                        | Fix                                                                             |
| ----------------------------------- | ------------------------------------------------------------------------------- |
| SDK not initialized                 | Call `await client.initialize()` before evaluating                              |
| Flag key typo or case mismatch      | Flag keys are case-sensitive — verify exact spelling                            |
| Flag not enabled in the environment | `PUT /flags/{flagId}/environments/{environmentId}` with `{ "isEnabled": true }` |
| Flag is archived                    | Unarchive by recreating it, or create a new flag                                |

## Symptom: Flag returns `false` when expected `true`

| Likely cause                                          | Fix                                                                                    |
| ----------------------------------------------------- | -------------------------------------------------------------------------------------- |
| Flag not attached to the environment                  | Create the flag-environment config: `PUT /flags/{flagId}/environments/{environmentId}` |
| Flag is disabled in the environment                   | Enable it via the Admin API or dashboard                                               |
| Flag is archived                                      | Archived flags always return `false`                                                   |
| Cache staleness                                       | Wait for cache TTL (default 60s) or call `client.refresh()`                            |
| Target environment differs from SDK key's environment | Verify the SDK key matches the environment you edited                                  |

## Symptom: Flag doesn't update after admin change

| Likely cause                                         | Fix                                                                                                |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| SDK cache TTL hasn't expired                         | Wait for TTL, or call `client.refresh()`                                                           |
| Server-side Redis cache not invalidated              | Cache has a 60s TTL — wait for it to expire, or check Admin service logs for invalidation failures |
| Poll interval hasn't elapsed                         | The SDK polls every `pollIntervalMs` (default 30s) — wait for the next poll                        |
| Flag was created but not enabled for the environment | New flags default to `isEnabled: false` per environment — enable explicitly                        |

<Note>
  If you need near-instant propagation for a specific flag, set `ttlOverrideSeconds` on the flag-environment configuration to a low value (e.g. 5 seconds).
</Note>

## Symptom: `401 Unauthorized`

| Context        | Likely cause                      | Fix                                                           |
| -------------- | --------------------------------- | ------------------------------------------------------------- |
| Admin API      | Missing, expired, or invalid JWT  | Re-authenticate via `POST /auth/login`                        |
| Admin API      | Using an SDK key instead of a JWT | Use your account's JWT access token, not the SDK key          |
| Evaluation API | Invalid or revoked SDK key        | Verify the key matches the environment; rotate if compromised |
| Evaluation API | Environment is revoked            | Create a new environment or rotate the key                    |

<Warning>
  The API returns the same `401` error for both "key doesn't exist" and "environment is revoked" — it does not distinguish them to prevent key enumeration.
</Warning>

## Symptom: `404 Not Found`

| Context         | Likely cause                             | Fix                                                                                 |
| --------------- | ---------------------------------------- | ----------------------------------------------------------------------------------- |
| Flag evaluation | Flag key misspelled or doesn't exist     | Verify the exact key spelling — keys are case-sensitive                             |
| Flag evaluation | Flag not configured for this environment | Enable the flag in the environment via Admin API                                    |
| Flag evaluation | Flag is archived                         | Archived flags return `false` (not 404) — but the flag won't appear in config fetch |
| Admin API       | Flag/environment/rule ID doesn't exist   | Verify the UUID is correct                                                          |

## Symptom: `409 Conflict`

| Context              | Likely cause                                               | Fix                                                     |
| -------------------- | ---------------------------------------------------------- | ------------------------------------------------------- |
| Flag creation        | Flag with same key already exists                          | Use a different key or archive the existing flag        |
| Rule creation        | Rule with same priority already exists                     | Choose a different priority value                       |
| Flag archival        | Flag is still enabled in one or more environments          | Disable the flag in all environments first              |
| Environment creation | Environment with same product+name already exists (active) | Use a different name, or revoke/delete the existing one |

## Symptom: SDK key visible in browser devtools

| Likely cause                                                       | Fix                                                                                                                                                                                         |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Using `REACT_APP_*` or `NEXT_PUBLIC_*` env var (bundled to client) | Confirm the flag is non-sensitive; or move evaluation to a [Server Component](/feature-flags/sdk/nextjs) using server-only env vars, or evaluate on your [backend](/feature-flags/sdk/node) |

## Symptom: Targeting rules don't match

| Likely cause                            | Fix                                                                                                                                                                                                                           |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SDK pre-evaluates with empty context    | The SDK does not pass per-request context to the evaluation engine. Use **Direct HTTP** (`POST /sdk/v1/evaluate`) for per-user targeting — see [SDK evaluation model](/feature-flags/reference/sdk-config#evaluation-methods) |
| Rule priority order is wrong            | Lower priority numbers are evaluated first; reorder                                                                                                                                                                           |
| Attribute name mismatch                 | Context keys must match exactly — `userId` not `user_id` or `user`                                                                                                                                                            |
| Unsupported operator                    | Only `==`, `!=`, `>`, `<`, `>=`, `<=` are supported — no `ends_with`, `starts_with`, or `contains`                                                                                                                            |
| Wrong value field                       | Use `valueString` for string type, `valueInt` for number, `valueBool` for boolean — not a generic `value` field                                                                                                               |
| `userId`/`tenantId` missing for rollout | Percentage rollouts require the bucketing key in context; without it, the user is treated as "not in rollout"                                                                                                                 |

## Symptom: Percentage rollout always returns same result

| Likely cause                              | Fix                                                                                                                                                                                 |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Using Direct HTTP with same user          | This is correct — FNV-1a is **deterministic**. The same `userId` always gets the same bucket. To change a user's bucket, change the rollout percentage or use a different `userId`. |
| Hash collision causing unexpected results | Verify your percentage threshold — `hash % 100 < percentage` means a 1% rollout only enables users whose FNV-1a hash mod 100 is 0.                                                  |
| `tenantId` used instead of `userId`       | `per_user` strategy hashes `userId`, `per_tenant` hashes `tenantId` — make sure they match                                                                                          |

## Symptom: Network errors on startup

| Likely cause                                      | Fix                                                                                  |
| ------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `baseUrl` is wrong                                | Verify the API URL (e.g. `https://flags.clubedge.live`)                              |
| Firewall / VPC restrictions                       | Ensure outbound access to the API host                                               |
| API not running                                   | Check the API service status; see [Health check](https://flags.clubedge.live/health) |
| `initialize()` called before network is available | Wrap in try/catch and retry with backoff                                             |

## Symptom: `cacheTtlSeconds` not behaving as expected

The config option `cacheTtlSeconds` is stored as-is and used directly as milliseconds in the cache's TTL. Despite the name:

* Default `60000` = 60 seconds (correct)
* `cacheTtlSeconds: 30` = **30 milliseconds**, not 30 seconds
* Use `60000` for 60 seconds, `300000` for 5 minutes

This is a known naming inconsistency in the SDK.

## Still stuck?

* Check the [Evaluation API reference](/feature-flags/reference/evaluation-api) for exact request/response shapes
* Check the [Admin API reference](/feature-flags/reference/admin-api) for endpoint details
* Review [audit logs](https://flags.clubedge.live/audit) for who changed what and when
* Contact the platform team: **Slack** `#feature-flags-support` or file an issue in the `feature-flags-platform` repo — include environment name, flag key, and timestamp
