Troubleshooting
Common errors and how to fix them
Common Errors
SDK Initialization Failed
- Cause (JS): Incorrect
sdkKeyor network issues - Cause (PHP): Incorrect
sdkKey, network issues, or no PSR-18 HTTP client installed - Cause (Android): Incorrect
sdkKeyor network issues — on a failed config fetch the SDK loads the last cached config from app-private storage; with no cache, decision methods returnnulluntil the next successful fetch - Cause (Ruby): Incorrect
sdk_key(orsdk_key_secret) or network issues — a failed config fetch is logged atwarnand decision methods return sentinels rather than raising;ConvertSdk.createitself raisesArgumentErroronly on misconfiguration (for example, neithersdk_key:nordata:supplied) - Cause (iOS): Incorrect
sdkKey(orsdkKeySecret) or network issues — on a failed config fetch the SDK loads the last-good config cached on disk (Application Support); with no cache,runExperiencereturnsnilandrunFeaturereturns a disabledFeatureuntil the next successful fetch.ready()is the only throwing call, and it throws only on an unrecoverable config error (emptysdkKey, or empty/invalid directconfigData) - Cause (Python): Incorrect
sdk_keyor network issues — unlike the mobile SDKs,Core(SDKConfig(...)).initialize()is fail-fast with no on-disk last-good cache: a malformed config raisesInvalidConfigErrorand a failed fetch raisesConfigLoadError(both subclasses ofConfigError). Wrapinitialize()intry/except ConfigErrorand decide your fallback. Direct-datainit makes no network call. - Solution: Verify the
sdkKeyand ensure network connectivity. If using an authenticated key, ensuresdkKeySecretis also provided. (PHP only) Install a PSR-18 HTTP client (e.g.,composer require guzzlehttp/guzzle).
No PSR-18 HTTP Client Found (PHP only)
- Cause:
php-http/discoverycannot find a PSR-18 HTTP client implementation - Error message:
No PSR-18 HTTP client found. Install one (e.g., guzzlehttp/guzzle ^7) or pass an explicit httpClient. - Solution: Install one:
composer require guzzlehttp/guzzleor any other PSR-18 compatible client.
User Context Creation Failed
- Cause (JS): Missing or invalid
userId - Cause (PHP): Missing or empty
visitorId, or SDK not initialized - Solution (JS): Ensure a valid, non-empty
userIdstring is provided tocreateContext(). - Solution (PHP): Ensure a valid, non-empty
visitorIdstring is provided tocreateContext(). Check thatisReady()returnstruebefore creating contexts. - Solution (Android):
createContext()with no arguments auto-generates and persists a UUID visitor id. Decision calls made before the SDK is ready returnnull(never throw) — gate them behindonReady { }. - Solution (Ruby): A blank or
nilvisitor_idmakescreate_contextreturnnil(with an error log) rather than raising — guard fornilbefore using the context. Subscribe to thereadyevent (or pass staticdata:) so contexts are created against an installed config. - Solution (iOS):
createContext(visitorId:attributes:)with novisitorIdauto-generates and persists a Keychain UUID. Decision calls made beforetry await sdk.ready()returnnil/ disabled features (never crash) —await sdk.ready()first. - Solution (Python):
create_context(visitor_id, ...)raisesRuntimeErrorif called beforeinitialize(). Becauseinitialize()is synchronous and returns a readyCore, there is no "created before ready" race to guard against — initialize first, then create contexts. Pass a stable, non-emptyvisitor_idfor deterministic bucketing.
Experience Not Found
- Cause: Incorrect
experienceKeyor experience not defined in the project - Solution: Verify the
experienceKeymatches exactly. Ensure the experience isactive(notdraftorpaused) and belongs to the correctenvironment. To QA a draft or paused experience on purpose, load it with a debug token — see QA & Preview.
Feature Not Found
- Cause: Incorrect
featureKeyor feature not linked to any experience - Solution: Verify the
featureKey. Ensure at least one active experience has a variation with afullStackFeaturechange linked to this feature.
Visitor Not Bucketed (RuleError)
- Cause: The visitor's properties or location don't match the experience's audience/location rules
- Solution (JS): Check that the
visitorPropertiesandlocationPropertiespassed to the method match the rules configured in Convert. See Rule Evaluation & Targeting for how rules are evaluated. - Solution (PHP): Check that the
visitorPropertiesandlocationPropertiesinBucketingAttributesmatch the rules configured in Convert. TheRuleErrorenum has two cases:RuleError::NoDataFound-- no matching data for the ruleRuleError::NeedMoreData-- insufficient data provided to evaluate the rule
- Solution (Ruby): A miss returns a frozen sentinel instead of a variation — detect it with
case variation.key when nil(every sentinel has anil#key), or checkvariation.error?. The sentinels areRuleError::NO_DATA_FOUND,RuleError::NEED_MORE_DATA, andBucketingError::VARIATION_NOT_DECIDED. Check that thevisitor_properties/location_propertiesyou pass match the rules configured in Convert. - Solution (iOS): A miss returns
nilfromrunExperience(and a disabledFeaturefromrunFeature), never an error — a rule mismatch, an inactive or unknown experience, an ineligible visitor, or a not-yet-ready SDK all yield a miss. Check that the scalarattributesyou pass tocreateContextmatch the rules configured in Convert; onlyString/Int/Double/Boolvalues are kept (nested values are dropped). - Solution (Python): A miss returns
Nonefromrun_experienceandrun_feature(and an empty list fromrun_experiences/run_features), never an error. For the why without guessing, callcontext.diagnose_experience(key)/diagnose_feature(key)— they return a typedDiagnosticReason(e.g.AUDIENCE_MISMATCH,EXPERIENCE_NOT_FOUND) and never raise on a miss. Check that theattributes/location_attributesyou pass match the rules configured in Convert.
Tracking Events Not Appearing
If requests return 200 OK but nothing appears in Live Logs, see HTTP 200 but No Live Logs below.
- Cause: Tracking is disabled, events are still queued, or the SDK key is invalid
- Solution (JS): Ensure
network.trackingis notfalsein the config. CallreleaseQueues()to flush pending events. Verify the SDK key. Check thatenableTrackingis notfalsein method attributes. - Solution (PHP): Ensure
network.trackingis notfalsein the config. CallreleaseQueues()orflush()to send pending events. Verify the SDK key. The shutdown handler should flush automatically in PHP-FPM, but in CLI scripts you may need to callflush()explicitly. - Solution (Android): Check that tracking wasn't disabled via
trackingEnabled(false)at build time,setTrackingEnabled(false)at runtime, orenableTracking = falseon the call. Offline events are queued durably and ship when connectivity returns — declareACCESS_NETWORK_STATEso the SDK can flush immediately on reconnect. - Solution (Ruby): Ensure
trackingis notfalsein the config (the global switch always wins over a per-call track). Callflush(aliasrelease_queues) to send pending events. The PID-guardedat_exithandler flushes on process exit, but whenflush_intervalis set tonil(Lambda / CLI) you must callflushexplicitly. Verifyenable_trackingis notfalsein the call attributes. - Solution (iOS): Ensure tracking isn't disabled at any of the three layers — static
ConvertConfiguration.networkTracking = false, runtimeawait sdk.setTrackingEnabled(false), or per-callenableTracking: false. Offline events are queued durably in Application Support and ship when connectivity returns; a backgroundURLSessionalso completes delivery after the app is suspended. - Solution (Python):
track_conversion(and the bucketing/activation event enqueued byrun_experience/run_experiences) only enqueues — it never sends over the network. Events deliver whenbatch_size(default 10) fills, when the opt-inauto_flush_interval_mstimer fires, on a best-effortatexithook, or when you callcore.flush(). In short-lived runtimes (Lambda / CLI) leaveauto_flush_interval_msunset and callcore.flush()explicitly before exit. If experiment exposures aren't appearing, verify you didn't passenable_tracking=Falseon the run call — it suppresses the bucketing event per call (default isTrue). AConversionStatus.GOAL_NOT_FOUNDresult (not an exception) means the goal key is absent from the loaded config — verify thesdk_keyand the goal key.
HTTP 200 but No Live Logs
The tracking server answers 200 OK even when it drops the events, so a successful response does not prove the events were recorded.
- Cause: The visitor ID contains a character outside
0-9,a-z,A-Z,.,-and_. A common example is an Auth0 user ID such asauth0|64f1c2…, or an email address. - Solution: Pass an ID that matches
^[0-9a-zA-Z._-]+$. If your own ID contains other characters, pass its SHA-256 hex digest instead. See Visitor ID Format. - Cause (direct endpoint only): The request uses a default HTTP client
User-Agent, so the bot filter drops it. - Solution (direct endpoint only): Set a
User-Agentthat containsConvertAgent/<version>. See Direct Tracking Endpoint.
Config Validation Failed (PHP only)
- Cause: The fetched or provided project configuration is malformed
- Solution: If using static
data, verify the structure matches the Convert Serving API format. If usingsdkKey, the CDN response may be temporarily invalid -- the SDK will throw aConfigValidationException.
Updated 10 days ago
Did this page help you?