Skip to main content
If something isn’t working, this is the first place to check. Start with the triage table, then open the matching section below for the fix.
Most often one of:
  1. DECIMAL_API_KEY is missing or wrong. Confirm with echo $DECIMAL_API_KEY — it should start with dai_sk_. If you’re using .env files, make sure they’re loaded before agent_config() or decimalai.init() runs.
  2. Wrong base URL. If you set DECIMAL_BASE_URL, it must point at the API:
  3. Nothing turns tracing on. decimalai.init(api_key="...") alone doesn’t capture traces. An agent built with its framework’s agent_config() (LangChain, OpenAI Agents, the OpenAI SDK, the Anthropic Messages API, the Gemini API, Pydantic AI) is traced by that call; on Google ADK, check that DecimalAIPlugin() is in the App your runner was built from. Without an agent_config(), add a framework flag, which traces only:
    See Capability comparison for each framework.
  4. Process exited before flush. The SDK buffers traces and flushes on a background timer. An atexit handler drains the buffer on normal interpreter shutdown, so most short-lived scripts are covered automatically. The gap is processes that are hard-killed (SIGKILL, os._exit(), a crash) before atexit runs. For those, flush explicitly before exit:
  5. Wrong workspace. SDK traces are routed solely by the API key you send them with. There is no team= or project= parameter and no DECIMAL_TEAM env var. Confirm the dashboard’s active workspace matches the key. See Teams & Workspaces for how routing resolves.
The API returns four status codes you’ll see most often. This table is the at-a-glance summary; the per-code detail follows in the accordions below.401 detail. Your API key is missing, malformed, or expired.
Re-issue the key in Settings → API keys. Creating a new key never revokes an old one, whatever you label it — follow Rotating a key to roll out the replacement and then revoke the old key explicitly.If an export from the dashboard answers 401, run it with an API key instead.
A monthly quota, usually traces ingested, answers 429 Too Many Requests, and detail names the metric:
A feature or cap your plan doesn’t include answers 402 Payment Required, with error set to a value such as feature_not_available or linked_skills_limit_exceeded.For a monthly quota, either:The dashboard banner shows your current usage. If usage feels too high, look for runaway tests or accidental dev traffic hitting prod keys.
This is safe to ignore — it means the resource already exists in an equivalent state.
  • Skill sync 409: the body hash already matches an existing version. No new version was created.
  • Registry install 409: you’ve already installed this skill in this org.
Both endpoints are idempotent by design.
You’re hitting the per-plan rate limit. Responses include Retry-After:
The SDK respects this automatically. If you’re calling the API directly, sleep for the indicated seconds.To reduce request count, send traces in batches instead of one-at-a-time. The SDK automatically batches when buffer thresholds are hit. For direct API use, hit POST /api/v1/traces/batch with up to 100 traces per call.See Errors for the full rate limit table.
Evaluations run asynchronously by default. After ingest:
  1. Background eval worker scores each trace against the active policy.
  2. Decision engine computes a unified verdict (pass / fail / review).
Common causes of missing verdicts:
  • No evaluators configured for the agent. Add one with Add evaluator on the agent’s Evals tab, or through /api/v1/evaluators. The five built-in checks alone don’t set a verdict.
  • Custom eval check failed silently. Check the trace detail page → “Eval Errors” section.
  • Background worker hasn’t caught up. New traces typically score within 30s. Refresh the dashboard.
The GitHub Action looks up the manifest by agent_name + the git ref it’s running against. If the manifest hasn’t been registered, the action skips the check.Fix: run scripts/init_for_decimal.py (or your equivalent) with DECIMALAI_MODE=manifest_only as a step before decimal-labs/regression-check@v1:
manifest_only mode runs the manifest-extraction code path without actually invoking your agent.That script must end in a decimalai.flush_manifest_for_ci(agent_name=..., chain=agent) call — building the agent alone registers nothing, and the Action then stops with “No candidate-manifest-id provided or discoverable”. See Step 1 of the regression-check guide for the full script.
The SDK ingests traces in a background thread by default — the request path should never block on network I/O. If you’re seeing latency added to your agent:
  1. Make sure you call decimalai.init() once at startup and reuse it — don’t construct new clients in hot paths.
  2. Confirm you’re on a current SDK (pip install -U decimalai); background flush has been the default for a long time.
For parent-child agent calls to show up as a tree, the parent must propagate the trace_id:If you’re using LangGraph, CrewAI, or the OpenAI Agents SDK, parent–child linkage happens automatically — just verify the agent is traced: by its agent_config(), or by the framework flag on decimalai.init(). For custom orchestrators, capture the parent’s trace ID and pass it to the child’s parent_trace_id:
The platform displays the tree as long as parent_trace_id is set on the child trace.

The silent no-ops

The SDK is deliberately fail-open: a misconfiguration degrades quietly instead of crashing your agent. These are the five places that bites, in the order people hit them.
Seeing a skill on the public registry doesn’t put it on your agent. Add it with decimalai skills add <name>, which goes on your project’s list or, once the project is connected, on the agent. Or use Add to an agent on the skill’s page, or Create editable copy for a copy you can change. Until then it isn’t on the agent’s list, and nothing warns you.
agent_config() lists each skill in one line and gives the model load_skill to read the rest. The model decides whether to open one. On the run’s trace, Offered without Loaded means it passed. If you call SkillRouter.build_prompt_fragment() yourself, there’s no load_skill, so only the one-line rows reach the model unless you pass inject_body=True to the SkillRouter.
On LangChain, the OpenAI Agents SDK, the OpenAI SDK, Pydantic AI, Google ADK, the Gemini API and the Anthropic Messages API, tracing alone gives an agent no skills: the init() flags and instrument() trace only, and an agent gets its prompt and skills only from its framework’s agent_config(), passed into your own agent. On LangChain that is create_agent(..., middleware=[agent_config(name).middleware]), and a LangChain run without the middleware says so once, in a warning. On the OpenAI Agents SDK it goes into its own Agent(...), on Pydantic AI into Agent(capabilities=[...]), on Google ADK into LlmAgent(...), with DecimalAIPlugin() in the App to trace, and on the OpenAI SDK, the Anthropic Messages API and the Gemini API into each model call, one support.run() per user message. agent_config() also gives the model the load_skill tool (kill switch: init(load_skill_tool=False) or DECIMALAI_LOAD_SKILL_TOOL=0). On CrewAI, instrument() leaves the skill loader off unless you pass enable_skill_loader=True, and so does init(crewai=True) given skills=False, or run with DECIMALAI_SKILLS=0 in the environment — good traces, zero skills, no warning. init(crewai=True) and DECIMAL_AUTO_TRACE=crewai turn the loader on. CrewAI has no tool loop, so it puts the skill list into the prompt, plus the top skill’s full body when the platform ranked the result by this turn’s message or the skill is the agent’s only one (init(inject_skill_body=False) keeps it to the skill list); enable_load_skill_tool is accepted there but dormant.
decimalai.init(langchain=True) (and every other framework flag) logs a warning and continues untraced when the framework package isn’t importable — your agent runs, nothing is recorded. The same applies to DECIMAL_AUTO_TRACE (auto-init warns and skips) and to the raw-provider flags (openai=True etc.), which soft-skip when the matching OpenInference instrumentor is absent. Fix: for a framework flag, install the matching extra, e.g. pip install "decimalai[langchain]"; for a raw-provider flag, install the instrumentor package the startup warning names, e.g. pip install openinference-instrumentation-openai. Then re-check startup logs.
The regression check needs two things before it can say anything real: a baseline manifest (recorded automatically on the Action’s first run, or by decimalai.init() running in production) and ingested traces to measure blast radius against. A fresh workspace legitimately reports “first run — no baseline” and then near-zero affected traces. That’s honesty, not breakage — reports gain weight over days as production trace volume accumulates.

Tracing

How auto-detection picks up your framework, how spans are stitched together, and what you can override.

Manifests

The capability matrix per framework — useful when “my tools/prompts aren’t being captured” is the actual problem.

Errors

Full list of error codes the API can return, and what each one means.

Still stuck?