Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/flagship/gotchas.md
1# Flagship Gotchas & Troubleshooting23## Common Errors45### Flag Always Returns Default Value67**Cause:** Flag is disabled (`enabled: false`), or no targeting rules match, or evaluation context is missing expected attributes.89**Solution:** Check these in order:10111. Is the flag enabled? (`"enabled": true`)122. Do your targeting rules match the context you're passing?133. Are you passing the right attributes in the evaluation context?1415```typescript16// ❌ BAD — no context, rules can't match17const val = await env.FLAGS.getBooleanValue("my-flag", false);1819// ✅ GOOD — pass context attributes that rules reference20const val = await env.FLAGS.getBooleanValue("my-flag", false, {21userId: "user-42",22plan: "enterprise",23});24```2526### TYPE_MISMATCH Error in Details2728**Cause:** Calling a typed method on a flag with a different type (e.g., `getBooleanValue` on a string flag).2930**Solution:** Use the method matching the flag's variation type.3132```typescript33// ❌ BAD — flag "checkout-flow" has string variations34const val = await env.FLAGS.getBooleanValue("checkout-flow", false);3536// ✅ GOOD37const val = await env.FLAGS.getStringValue("checkout-flow", "original");38```3940### 409 Conflict on Flag Creation4142**Cause:** A flag with that key already exists in the app.4344**Solution:** Use a different key, or GET + PUT to update the existing flag.4546### Inconsistent Rollout Results4748**Cause:** `targetingKey` (or the configured bucketing attribute) is missing from the evaluation context, causing random bucketing on each request.4950**Solution:** Always pass a stable identifier:5152```typescript53// ❌ BAD — no targetingKey, rollout is random per request54const val = await env.FLAGS.getBooleanValue("gradual-rollout", false);5556// ✅ GOOD — stable userId for consistent bucketing57const val = await env.FLAGS.getBooleanValue("gradual-rollout", false, {58userId: sessionUserId,59});60```6162### Update Overwrites Entire Flag6364**Cause:** PUT replaces the full `FlagDefinition`. Sending only changed fields deletes the rest.6566**Solution:** Always read-modify-write:6768```bash69# ❌ BAD — overwrites the entire flag, losing rules/variations70curl -X PUT -d '{"enabled": true}' ...7172# ✅ GOOD — GET first, modify, PUT back73FLAG=$(curl -s -H "Authorization: Bearer $TOKEN" "$URL/flags/my-flag" | jq '.data')74UPDATED=$(echo "$FLAG" | jq '.enabled = true')75echo "$UPDATED" | curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d @- "$URL/flags/my-flag"76```7778### FLAG_NOT_FOUND in Client Provider7980**Cause:** Flag key not included in `prefetchFlags` array.8182**Solution:** Add the flag key to `prefetchFlags` when initializing `FlagshipClientProvider`.8384### Client Provider Token Exposure8586**Cause:** The `authToken` passed to `FlagshipClientProvider` is visible in the browser. It can evaluate flags across all apps in the account.8788**Solution:** Use a token with minimal permissions (Flagship Evaluate only). Never use a token with write/management permissions in the browser.8990---9192## Limits9394| Limit | Value | Notes |95|-------|-------|-------|96| Flag key length | 1-64 chars | Alphanumeric, hyphens, underscores only |97| Flag key pattern | `/^[a-zA-Z0-9_-]+$/` | — |98| Variation value size | 10KB max | Per variation, serialized |99| Variation name length | 64 chars max | Alphanumeric, hyphens, underscores |100| Description length | 512 chars max | Nullable |101| App name length | 1-64 chars | Alphanumeric, hyphens, underscores |102| Logical nesting depth | 6 levels | AND/OR conditions |103| Mutation rate limit | 60 / 60s | Per account:app |104| Read rate limit | 600 / 60s | Per account:app |105| Rollout percentage | 0-100 | Integer |106| Rule priorities | Unique integers >= 1 | Lower = evaluated first |107108---109110## Anti-Patterns111112### Evaluating Flags in a Tight Loop113114Flag evaluation via the binding is fast but not free. Avoid evaluating the same flag repeatedly in a loop — evaluate once and reuse the result.115116```typescript117// ❌ BAD118for (const item of items) {119const enabled = await env.FLAGS.getBooleanValue("my-flag", false, ctx);120// ...121}122123// ✅ GOOD124const enabled = await env.FLAGS.getBooleanValue("my-flag", false, ctx);125for (const item of items) {126// use `enabled`127}128```129130### Using the SDK Inside Workers When Binding Is Available131132The binding avoids HTTP overhead entirely. Only use the SDK inside Workers when you specifically need OpenFeature vendor-neutrality.133134```typescript135// ❌ Unnecessary HTTP overhead inside a Worker136const provider = new FlagshipServerProvider({137appId: "...", accountId: "...", authToken: "...",138});139140// ✅ Use the binding directly, or pass it to the SDK141const provider = new FlagshipServerProvider({ binding: env.FLAGS });142```143144### Partial PUT Updates145146The flag update API (PUT) requires the complete `FlagDefinition`. Sending only changed fields silently drops everything else. Always GET first, then modify and PUT back the full object.147148### Stale Flag Cleanup149150Flags that are disabled and no longer referenced in code should be deleted. Stale flags clutter the dashboard and make it harder to understand which flags are active. Follow the safe deletion workflow in `patterns.md`.151152---153154## Propagation Behavior155156Flag changes propagate globally within seconds. During the brief propagation window, some regions may serve the previous value. After propagation completes, all evaluations return the updated value.157158- No Worker redeployment needed for flag changes.159- If the dashboard is temporarily unavailable, evaluation continues using the last propagated configuration.160- Flag changes made via the REST API and dashboard are equivalent — both trigger propagation.161