---
title: Debugging
description: "A practical workflow for finding out why a kScript script is wrong: plot what you cannot see, read the diagnostics, isolate, and check the usual suspects."
---

<div class="flex gap-3 mb-6">
  <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-yellow-50 text-yellow-600 text-sm font-medium">
    Guide
  </span>
  <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-gray-100 text-gray-600 text-sm font-medium">
    5 min read
  </span>
</div>

Your script runs but the signal is wrong, or it draws nothing, or a line is mysteriously flat. There is no `console.log` on a chart, but there is a fast, reliable workflow. Work it in order.

## 1. Plot what you cannot see

The fastest debugger in kScript is a plot. You cannot step through the bar loop, but you *can* draw any intermediate value and look at it. When a calculation is suspect, put it on the chart.

Two tools:

- **`plotLine`** the intermediate series. Seeing the shape of a value over every bar usually tells you immediately whether it is doing what you think.
- **`plotText`** to print the exact number on the latest bar. When you need the precise value, not just the shape, render it as text.

```javascript title="scripts/probes/debugging/debug_by_plotting.ks"
//@version=2
define(title="Debug By Plotting", position="offchart", axis=true)

timeseries d = ohlcv(symbol=currentSymbol, exchange=currentExchange)

// When a value looks wrong, plot it directly to see what the engine computes.
timeseries spread    = d.high - d.low
timeseries spreadPct = d.close > 0 ? spread / d.close * 100 : 0

plotLine(value=spreadPct, colors=["#ef4444"], width=2, label=["Bar range %"], desc=["high minus low as a percent of close, plotted to inspect it"])

// Print the exact latest value as a label so you can read the number off the chart.
if (isLastBar) {
  plotText(text="".concat("range% = ", math.round(spreadPct[0] * 100) / 100), price=spreadPct[0], color="#f59e0b", size=12)
}
```


The red line is the intermediate value (bar range as a percent of close) drawn across every bar, so you can watch how it behaves. The text label on the last bar prints the exact current number, rounded for readability. When your real script misbehaves, lift the suspect expression into its own `timeseries`, plot it like this, and the bug usually becomes visible at a glance: a value pinned at zero, a line that flatlines, a spike where there should be none.

This works for any expression. Wrap the part you doubt in a `plotLine`, ship it offchart, and read the answer off the chart instead of guessing.

## 2. Read the runtime diagnostics

If a script compiles and runs but draws nothing, it is usually not a hard error. kScript catches the "ran but blank" cases and surfaces a **runtime diagnostic** in the editor instead of leaving you with an empty panel. Each has a code that points straight at the cause:

- `COMPUTE_ZERO_BARS` means no source data reached the bar loop. Nothing iterated, so nothing drew.
- `COMPUTE_ALL_NAN` means a plotted series was `na` on every bar: an indicator that never warmed up, a wrong source member, or an anchor that never reset.
- `RENDER_SPARSE_OUTPUT` means very few finite points relative to the bar count, often a condition that almost never fires.

These codes are the engine telling you exactly where to look. The full table, with every code, its severity, and the matching fix, is in [Common Errors](/kscript/faq/common-errors). Read the diagnostic first; it frequently saves you the whole hunt.

## 3. Isolate

When several things are plotted and one is wrong, stop reasoning about all of them at once. Comment out plots until only the suspect series remains, then narrow until the bad value is obvious.

```javascript
// plotLine(value=fast, ...)
// plotLine(value=slow, ...)
plotLine(value=signal, colors=["#ef4444"], width=2, label=["Signal"], desc=["the one series under investigation"])
```
Reducing the script to a single output removes every distraction and lets the diagnostics speak about exactly the value you care about. Once that one series is correct, bring the others back one at a time. This is the cheapest way to find which input poisoned a calculation downstream.

## 4. The usual suspects

Most "wrong script" bugs are one of a handful of patterns. Scan this list against your symptom:

- **Flat or blank line.** A series-returning value got held in a `var` instead of a `timeseries`, so it kept only the current scalar and lost its shape. Promote it to `timeseries`. (See [Variables](/kscript/core-concepts/core-variables) for the `var` vs `timeseries` split.)
- **Line starts blank, then appears.** The indicator has not warmed up. Anything with a period (a 50-bar EMA, an RSI) is `na` until it has enough bars. That leading gap is expected; make sure your logic tolerates `na` before the period fills.
- **Flat or blank anchored value.** Too little loaded history. An anchored calculation that never crosses its anchor boundary (a monthly anchor inside a window shorter than a month) stays `na`. Load more bars or pick a shorter anchor.
- **"Zero bars to compute."** No source reached the loop. An offchart script with no source has no timeline to walk. Add an `ohlcv(symbol=currentSymbol, exchange=currentExchange)` anchor so the bar loop has data, even if the indicator does not obviously use price.
- **Everything is `na` for no clear reason.** A wrong source member. Member names are not checked at compile time, so reading `funding.close` when the field is `funding.value` silently yields `na` on every bar. Check the member list for that source type in [Data Sources](/kscript/core-concepts/data-sources).

Walk these top to bottom. The fix for each is one line, and the diagnostic from step 2 usually tells you which one you are looking at.

## See also

- [Common Errors](/kscript/faq/common-errors) for the full diagnostic table and every hard-error message.
- [Execution Model](/kscript/core-concepts/execution-model) for why a script needs a source to reach the bar loop.
- [Plotting](/kscript/functions/plotting) for `plotLine`, `plotText`, and the rest of the output family.
