SDK Troubleshooting Guides

View as Markdown

Installation, Initialization & Environments

Initialization fails with type/runtime errors when config values have the wrong shape (for example, passing a string where an object is expected).

Root Cause
Initialization parameters do not match the expected data types (e.g., passing stringified JSON instead of a raw object), or Marketplace app configuration schemas are misaligned with defined parameter shapes.

Resolution

  1. Validate the SDK initialization object against the SDK README/types.
  2. Ensure nested options (proxy/retry/cache/plugin options) are objects, not stringified JSON.
  3. For Marketplace apps, verify config schema matches app parameter definitions.

SDK initializes without exception and the first API call returns a 2xx JSON response. Escalate with a redacted config object and full stack trace if error persists.

Runtime/module parse errors can occur when project Node runtime is incompatible with package expectations.

Root Cause
The project's Node.js runtime version falls outside the supported range of the specific SDK or CLI package, causing syntax errors or module parsing failures during execution.

Resolution

  1. Check node -v.
  2. Use an Active LTS Node version unless the specific SDK/CLI package documents different requirements.
  3. Reinstall dependencies after runtime switch.
  4. Avoid blanket downgrade guidance. Align Node version per package constraints in your lockfile/CI.

Install/import completes and sample SDK calls run without syntax/module loader errors.

SSR builds/runtime can fail when browser-only assumptions leak into server execution paths.

Root Cause
Browser-specific objects (like window or document) are referenced during server-side execution, or the SDK is initialized as a global singleton that cannot persist across stateless server requests.

Resolution

  1. Initialize SDK with contentstack.stack(...) in server-safe modules.
  2. Keep browser-only logic behind typeof window !== 'undefined' checks.
  3. Pass explicit environment/region in config for deterministic server behavior.
  4. Avoid older constructor/global-singleton patterns in SSR code.

Server render completes and fetch returns 2xx without window is not defined or similar runtime errors. Escalate with framework version and minimal initialization snippet.

The SDK fails to initialize or connect with "Undefined" values because it cannot successfully read the API Key or Token from local .env files.

Root Cause
The SDK is imported or initialized before the application has finished loading .env files, or there is a naming mismatch between the system environment keys and the code.

Resolution

  1. Load env variables before any SDK initialization/import side effects.
  2. Match env key names exactly between .env and code.
  3. Restart runtime after changing .env.

Startup shows non-empty required env vars (redacted), and the first SDK call returns 2xx. Escalate with startup order snippet and SDK version if envs are present but init still fails.

Browser runtime errors occur when Node-only globals/modules are pulled into client bundles.

Root Cause
The application is attempting to use Node.js-specific modules (like Buffer) in a client-side browser environment without the necessary polyfills or the use of a browser-safe SDK build.

Resolution

  1. Upgrade to the latest supported SDK/browser-safe package build.
  2. Remove Node-only imports from client-side bundles.
  3. Add polyfills only when upgrade/refactor is not immediately possible.

Browser flow completes without Buffer being defined, and SDK calls return expected data. Escalate with bundler config and import graph if error persists.

Installing the SDK results in a "Peer Dependency Conflict," preventing installation in projects using specific versions of React or Node.

Root Cause
Version mismatches between the SDK’s requirements and the existing project dependencies (e.g., React or Node.js versions) prevent the package manager from resolving a stable dependency tree.

Resolution

Install failures often come from incorrect package names or incompatible dependency trees.

  1. Install correct SDK packages for the use case:
    • @contentstack/delivery-sdk
    • @contentstack/management
  2. Align Node and package manager versions with project/toolchain constraints.
  3. Resolve lockfile conflicts explicitly; use bypass flags only as a temporary debugging step.
npm i @contentstack/delivery-sdk
npm i @contentstack/management

Packages install successfully and import without unresolved dependency conflicts. Escalate with lockfile excerpt, package manager version, and full install error output.

Authentication, Regions & Networking

SDK requests return 401 Unauthorized when a token type does not match the SDK/API being used (for example, using a CMA token with the Delivery SDK).

Root Cause

A mismatch exists between the API being called and the token provided, such as using a Management Token for Delivery API calls or a token from a different stack.

Resolution

  1. Use the correct token for the SDK:
    • Delivery SDK -> Delivery Token
    • Management SDK -> Management Token / Auth Token
  2. Confirm that the API key and token were generated from the same stack.
  3. For Delivery SDK calls, verify the token has access to the configured environment.

A fetch call returns 200 with a non-empty payload and no 401 response. Escalate if a token is active in UI but still rejected. Share stack UID, SDK package name/version, and request ID if available

Content type updates via CMA fail with 403 when the token role/scope/policy does not allow model changes.

Root Cause

The provided token lacks the necessary administrative permissions/roles to modify schemas, or the request originates from an IP address not included in the stack’s allowlist.

Resolution

  1. Ensure the token role has content model update permissions (typically admin-level).
  2. Confirm IP allowlist/policy permits the calling host.
  3. Validate stack limits or governance policies are not blocking changes.

update() returns 2xx, and schema changes appear in UI/API. Escalate if owner/admin role still receives 403; include request ID and sanitized payload.

Some corporate gateways block requests unless expected headers are present or match policy.

Root Cause

Corporate firewalls or security gateways are configured to drop requests that lack specific identification headers or custom security metadata.

Resolution

  1. Do not assume SDK omits identification headers by default.
  2. If policy requires extra headers, add approved custom headers in your request/plugin layer.
  3. Validate upstream proxies are not stripping headers before the request reaches Contentstack.
  4. Coordinate with network/security team on allowlist rules for SDK traffic.

Requests return 2xx, and WAF logs confirm expected headers/policy match. Escalate with sanitized gateway logs and request ID when blocked despite compliant headers.

Using default region/host against non-US stacks can produce auth/key mismatch symptoms.

Root Cause

The SDK is defaulting to the US region host while the target stack is hosted in a different region (e.g., EU or AU), causing a "Stack Not Found" or invalid key error.

Resolution

  1. Set explicit region in SDK initialization.
  2. Use valid region constants supported by the SDK (for example Region.EU, Region.AU, Region.AZURE_NA, Region.AZURE_EU, Region.GCP_NA, Region.GCP_EU in Delivery TS SDK).
  3. Ensure API key/token are from the same regional stack.

Region-configured calls return 200 from the correct regional host. Escalate if region is correct but key is still rejected; include stack UID, region, and request host.

Scripts using the SDK with an Authtoken (user session) fail after a few hours, resulting in 401 Unauthorized as the session expires.

Root Cause

User-session Authtokens have a limited lifespan and expire, causing long-running background scripts to fail once the initial session token becomes invalid.

Resolution

Long-running scripts using user session auth can fail when session tokens expire.

Do

  1. Use management_token for long-running, non-interactive server jobs.
  2. Keep auth mode explicit per workflow (management_token, authtoken, or OAuth bearer).
  3. Handle 401 with a controlled re-auth/refresh path, then retry only safe/idempotent operations.
  4. Configure retry strategy for 429/5xx separately from authentication renewal.

Don't

  1. Don't run long background automation on user authtoken unless you own renewal logic.
  2. Don't assume a generic login() call automatically refreshes tokens in every SDK flow.
  3. Don't mix authorization and authtoken headers in the same request path.
  4. Don't retry 401 indefinitely without rotating or re-establishing credentials.

Long-running job completes without late-stage 401 failures, and any forced token rollover recovers via the defined re-auth path. Escalate with job duration, auth mode (management_token/authtoken/OAuth), retry settings, and first 401 timestamp/request ID.

Users cannot log in to the CLI (csdx auth:login) despite using correct credentials, receiving an "Invalid Credentials" or "MFA Required" error.

Root Cause

Authentication fails due to incorrect region settings in the CLI config, or the user has failed to complete the required Multi-Factor Authentication (MFA) challenge.

Resolution

  1. Use csdx auth:login and complete the built-in MFA/OTP flow when prompted (or use --oauth for SSO flows).
  2. Confirm configured region before retrying auth (csdx config:get:region / csdx config:set:region).

csdx auth:login succeeds, csdx auth:whoami prints the logged-in email, and csdx config:get:region shows the expected region. Escalate through CLI support path with CLI version, exact login command used, region config output, and auth logs.

Querying, References & Content Retrieval

Developers are unable to distinguish between "Draft" (unpublished) and "Published" entries when using the Management SDK for auditing or migration.

Root Cause

The Management SDK (CMA) returns all entries by default regardless of status; the publish_details metadata must be explicitly requested and inspected to verify live status.

Resolution

  1. Fetch entries using CMA with include_publish_details: true.
  2. Inspect publish_details in the response.
  3. Treat empty publish_details (or version mismatch logic in your workflow) as unpublished/draft-like state.

Example:

const entry = await client
.stack({ api_key: process.env.CS_API_KEY })
.contentType('blog')
.entry('entry_uid')
.fetch({ include_publish_details: true });

The programmatic output correctly identifies which entries are live and which are drafts. Escalate if publish_details are missing for entries known to be published. Provide Entry UID.

The SDK returns a 422 Unprocessable Entity error when query methods (like filters or includes) use unsupported or misspelled parameters.

Root Cause

The query uses misspelled parameters, unsupported filter methods for a specific field type, or hidden characters that violate API validation rules.

Resolution

  1. Check the SDK method syntax; ensure you are using the correct helper methods (e.g., .includeCount() vs manually adding parameters).
  2. Verify that parameters like include_fallback are supported for the specific content type.
  3. Ensure no trailing spaces or hidden characters exist in the parameter strings.

The query executes successfully and returns the expected count or localized content. Escalate if the same query works via cURL but fails via SDK. Provide the generated request URL.

Published entries can still return 404 when the environment/locale/region does not match the publish target.

Root Cause

The request is targeting a different environment or locale than the one where the entry was successfully published.

Resolution

  1. Confirm entry is published to the same environment used by SDK config.
  2. Ensure locale code matches exactly.
  3. Verify region/host alignment for the stack.

Entry fetch returns 200 and expected UID for requested environment/locale. Escalate with entry UID, environment, locale, and region used in request.

Reference fields may return empty arrays/UID-only data when references are not explicitly expanded or not publish-aligned.

Root Cause

Reference fields are not explicitly expanded using .includeReference(), or the referenced entries have not been published to the target environment.

Resolution

  1. Use includeReference(...) for required reference fields.
  2. For nested refs, include dotted paths as needed.
  3. Verify referenced entries are published to the same environment/locale as the parent entry.

Response returns populated referenced objects (not empty arrays for valid linked data). Escalate with parent entry UID, reference field UID/path, and publish targets.

Developers cannot programmatically access "Last Modified By" or "Owner" details via the SDK, as these are excluded from default responses for performance.

Root Cause

Metadata fields like "Owner" or "Last Modified By" are excluded from standard entry responses to optimize performance and must be requested via specific inclusion parameters.

Resolution

  1. Use CMA (not Delivery SDK) for metadata workflows.
  2. Fetch entry-level metadata through documented entry params:
    • entry(uid).fetch({ include_workflow: true, include_publish_details: true })
  3. Fetch action/user audit trail through stack audit-log APIs:
    • stack.auditLog().fetchAll({ include_count: true, limit, skip })
    • stack.auditLog('log_uid').fetch()
  4. Verify the token has read access for the stack objects being queried.
const entry = await client
.stack({ api_key: process.env.CS_API_KEY })
.contentType('blog')
.entry('entry_uid')
.fetch({ include_workflow: true, include_publish_details: true });

const logs = await client
.stack({ api_key: process.env.CS_API_KEY })
.auditLog()
.fetchAll({ include_count: true, limit: 10, skip: 0 });

Entry fetch returns metadata fields (including workflow/publish context), and audit-log calls return actor/action records for the stack. Escalate with entry UID, audit-log request params, token type, and sample response payload if metadata is still missing.

The SDK returns content in the master language even when a different locale is requested, or it returns a 404 if the locale is not properly specified.

Root Cause

The query does not explicitly define the .locale() parameter, or the requested locale code does not match the exact casing/format defined in the stack.

Resolution

  1. Use .locale('locale-code') on Delivery SDK queries/entry fetches.
  2. Confirm the target locale is enabled and published for the entry.
  3. Use exact locale code casing/format as defined in stack locales.
const localizedEntry = await stack
.contentType('article')
.entry('entry_uid')
.locale('fr-fr')
.fetch();

Returned fields contain localized values (or expected fallback behavior if locale content is unavailable). Escalate with entry UID, locale code, and publish evidence when locale data is still missing.

Data contained within a Global Field is missing from the final SDK response, even though other entry fields are present.

Root Cause

The field is restricted by role-based permissions, or the global field schema was updated without re-publishing the affected entries.

Resolution

Global field payload may appear missing due to model visibility, permission, or publish-state mismatch.

  1. Verify the global field is not hidden/restricted in the content model.
  2. Confirm token roles can access the field data.
  3. Re-publish content type/entries if model updates were recent.

Entry response includes expected global field object for the published target. Escalate with content type UID, field UID, and role/token details.

Caching, Sync & Performance Limits

Large payloads (many assets/references) can trigger request timeout failures.

Root Cause

Single requests attempting to fetch massive payloads (e.g., 100+ deep references) exceed the default network timeout limits of the SDK or environment.

Resolution

  1. Reduce payload size with pagination (limit/skip) and smaller batches.
  2. Increase SDK timeout only as needed for network conditions.
  3. Split deep data hydration into phased requests instead of one oversized query.
const result = await stack
.contentType('article')
.entry()
.query()
.limit(20)
.skip(0)
.find();

Paginated requests return 200 consistently with no timeout error. Escalate if timeouts persist on small paginated batches; include region, timeout setting, and stack UID.

Stale content appears when cache policy/persistence settings prioritize cache over freshness.

Root Cause

The SDK’s cache policy is set to prioritize local persistence (e.g., CACHE_ELSE_NETWORK) over real-time API data, causing the application to serve stale content.

Resolution

  1. Use modern cache policy configuration (cacheOptions.policy) for your freshness requirement.
  2. Prefer network-first patterns for dynamic/live content paths.
  3. Ensure persistence store TTL/maxAge and cache invalidation strategy are intentional.
  4. Remove guidance relying on legacy/non-standard cache clearing methods.
cacheOptions: {
policy: Policy.NETWORK_ELSE_CACHE,
persistenceStore: new PersistenceStore({ storeType: 'localStorage', maxAge: 3600000 })
}

Recently updated entries return latest updated_at/content after policy changes. Escalate with cache policy, persistence config, and timestamps of publish vs fetch.

High-concurrency scripts hit platform/API rate limits and receive 429.

Root Cause

High-concurrency scripts exceed the platform’s rate limits by sending too many simultaneous requests without exponential backoff or throttling.

Resolution

  1. Use retry with exponential backoff in application logic.
  2. Reduce parallelism and batch requests.
  3. Use SDK-supported bulk operation endpoints/methods where applicable.
  4. In CMA JS flows, configure retry settings intentionally (retryOnError, retryLimit).
const client = contentstack.client({
authtoken: process.env.CS_AUTHTOKEN,
retryOnError: true,
retryLimit: 5
});

Bulk workflow completes successfully without terminal 429 failures. Escalate if 429 appears at low request volume; share request rate, source IP, and stack UID.

The SDK's Sync API returns an error or stops processing when it encounters a deletion event in the sync queue.

Root Cause

The application logic fails to distinguish between entry updates and entry_deleted event types in the Sync API response, leading to processing errors for non-existent UIDs.

Resolution

Sync consumers break when deletion events are treated like normal entry payloads.

Use one of the following supported patterns based on your sync architecture:

  1. Client-side event switch (default):
    • Process all syncData.items by item.type
    • Remove local records for entry_deleted
  2. Server-filtered delete sync jobs:
    • Run stack.sync({ type: 'entry_deleted' }) for cleanup-focused workers
  3. Tokened incremental strategy (recommended at scale):
    • Drain batches with pagination_token
    • Persist and continue with sync_token for delta runs
    • Apply delete events before any re-fetch/re-hydration logic
const syncData = await stack.sync({ syncToken: lastSyncToken });
for (const item of syncData.items) {
if (item.type === 'entry_deleted') {
// remove from local store
}
}

// Example server-filtered delete run:
const deletedOnly = await stack.sync({ type: 'entry_deleted' });

Sync completes with 200, delete events are consumed without exceptions, and local state no longer contains deleted entry UIDs after reconciliation. Escalate with sync mode used (full/mixed/deleted-only), sync_token/pagination_token, failing item payload, and local-store reconciliation logs.

Asset Transformations & UI Rendering

Developers attempt to resize an asset using SDK helper methods (e.g., .width(200)), but the resulting URL does not contain the transformation parameters.

Root Cause

Transformation methods are being chained on the URL string directly rather than using the ImageTransform class required by modern SDK versions to generate valid query parameters.

Resolution

Legacy chaining assumptions can generate unchanged URLs when transformation objects are not applied correctly.

  1. Build transform instructions with ImageTransform.
  2. Apply transformation through the SDK URL transform API.
  3. Confirm the asset is an image and not a non-transformable file type.
import { ImageTransform, Format } from '@contentstack/delivery-sdk';
const transform = new ImageTransform().resize({ width: 200 }).format(Format.PJPG);
const transformedUrl = assetUrl.transform(transform);

The generated URL contains expected transform parameters (for example width=200) and transformed asset loads. Escalate with original URL, transformed URL, and asset MIME type.

Content from Markdown fields is returned as raw Markdown syntax in the SDK response, leading to formatting issues on the live site.

Root Cause

Contentstack APIs return raw data (Markdown or JSON RTE) to maintain a headless architecture; the responsibility of parsing and rendering this data lies with the frontend application.

Resolution

SDK responses intentionally return raw markdown content; HTML rendering is application responsibility.

  1. Classify the field first:
    • Markdown field -> expect raw markdown string from SDK.
    • JSON RTE field -> expect structured JSON, not pre-rendered HTML.
  2. For JSON RTE content that includes embedded entries/assets, fetch with SDK query helpers such as .includeEmbeddedItems().
  3. For reference fields used in render paths, include linked content using .includeReference(...) where needed.
  4. Render in the application layer:
    • Markdown -> parse with your app’s markdown renderer.
    • JSON RTE -> render through your rich-text renderer/component pipeline.
  5. Sanitize final HTML output according to frontend security policy before DOM injection.
  6. If output is still raw, verify the UI render path is not escaping HTML as plain text.

API response returns raw markdown/JSON RTE as expected, and frontend render output shows formatted HTML with embedded items resolved where configured. Escalate with field type (Markdown vs JSON RTE), sample payload, query helper usage (includeEmbeddedItems/includeReference), and renderer configuration.