Pine Script debugging: find and fix errors

Autoview · Guide · Updated October 5, 2026

Pine Script has no step-through debugger. You debug by making the script show you its own values: on the chart, in the Data Window, in a log, or in a label. This page covers each of those, then the check that matters before automation: confirming the exact text your alert sends to Autoview.

Two kinds of error

The Pine manual splits errors into two groups, and they show up in different places.

  • Compilation errors happen before the script runs on any data. The Pine Editor highlights the problem code in red and shows a message saying what is wrong. Fix these first, because nothing else runs until they are gone.
  • Runtime errors happen while the script runs on a dataset, under specific conditions. The script stops and a red exclamation point icon appears in its status line on the chart.

Each documented error has a code (CE for compilation errors, CW for warnings, RE for runtime errors), and the manual's errors overview links each code to its own page with the fix.

Syntax errors on wrapped lines

If the editor flags a line you split across two or more lines, check its indentation first. The manual's rule: a continued line can use any indentation except a multiple of four spaces, because four spaces or a tab start a new local block. Code inside parentheses or square brackets has no such limit.

//@version=6
indicator("Wrap example")
// continued line indented 2 spaces, not 4
total = open + high +
  low + close
// inside parentheses, any indentation works
avg = math.avg(open,
    close)
plot(total / 4 - avg)

Plot the value you are unsure about

plot() is the quickest way to see a number on every bar. The line on the chart shows its history, and the status line, price scale and Data Window show the value on the bar under your mouse pointer. If you don't want the debug line drawn over price, keep it out of the pane with the display argument:

//@version=6
indicator("Debug RSI", overlay=true)
rsi = ta.rsi(close, 14)
plot(rsi, "rsi", display=display.all - display.pane)

Open the Data Window and move along the chart: the rsi value updates for each bar. A plotted condition shows 1 when it is true and 0 when it is false, which is a fast way to see exactly which bars a signal fired on. plotchar() does the same job with a character drawn on the chart:

crossUnder = ta.crossunder(rsi, 30)
plotchar(crossUnder, "crossUnder", "▼", location.top)

A script can have at most 64 plots, so remove debug plots once the question is answered.

Log values with log.info() and Pine Logs

For text, or for values you want to read one bar at a time, use the log functions. log.info() writes a gray message, log.warning() an orange one and log.error() a red one. Each takes a plain string or a format string with arguments:

if crossUnder
    log.info("RSI crossed under 30: {0}", rsi)

Open the Pine Logs pane from the More menu in the Pine Editor, or from the More menu in the script's status line on the chart. On historical bars each log.info() call logs once per bar; on realtime bars it can log on any tick. The pane keeps up to 10,000 historical messages.

One limit to know: only personal scripts can write Pine Logs. A published script cannot.

Put the value on the chart with a label

A label shows text at a bar, right where the event happened. Convert numbers to text with str.tostring():

if crossUnder
    label.new(bar_index, high, "rsi " + str.tostring(rsi, "#.##"))

A script can show at most 500 labels, so older ones disappear on a long chart. Plots or logs suit values you need on every bar; labels suit rare events.

Check the message that reaches Autoview

Once the logic works, the last thing to verify is the alert text itself, since that string is the command Autoview executes. Here the quantity is computed on each bar, so it is the value worth checking. Build it once, then send the same variable to both the log and the alert, so what you read in Pine Logs is exactly what the alert sends:

if crossUnder and barstate.isconfirmed
    qty = math.round(100 / close, 5)
    msg = "s=BTCUSDT b=buy t=market d=1 q=" + str.tostring(qty)
    log.info(msg)
    alert(msg, alert.freq_once_per_bar_close)

The d=1 in that message is Autoview's dry run: Autoview logs what the command would do and returns before any order is sent. Let it fire a few times, then compare the Pine Logs line with the matching entry in your Autoview log. When they match and the command reads right, remove d=1.

A note on what Autoview is. Autoview is an execution tool, not a trading or investment advisor. It places the orders your alerts tell it to; it doesn't generate signals or make any claim about results. Trading carries risk of loss, and you're responsible for the strategy you automate. See our disclosures.

Read the Pine Script basics guide