Pine Script error: Cannot use 'plot' in local scope (how to fix)
Fix the Pine Script error "Cannot use 'plot' in local scope": move plot() out of the if block or function and make the plotted value conditional instead.
TradingView shows "Cannot use 'plot' in local scope" when a plot() call sits inside an if block, a for loop or a function body. Pine has to know every plot when it compiles the script, so a plot that only exists on some bars is not allowed. The fix is to keep plot() at the top level of the script and make the value conditional, for example plot(cond ? v : na).
What causes it
"Local scope" means any indented block: the body of an if, a for or while loop, or a function you wrote with =>. Code at the left margin is the global scope. plot() is only allowed there.
plot() inside an if block
The most common version. The writer wants a line only while price is above an average, so they wrap the plot in a condition. This code FAILS on TradingView:
//@version=6
indicator("Local plot", overlay=true)
fast = ta.ema(close, 9)
if close > fast
plot(fast)
Line 5 is indented under the if, so the plot is in local scope.
plot() inside your own function
A helper function that draws something for you looks tidy, but it puts the plot in the function's body. This also FAILS on TradingView:
showEma(len) =>
plot(ta.ema(close, len))
The same applies to a plot() placed inside a for loop. Wherever the indented block comes from, the plot has to move out of it.
How to fix it
Turn the question around. Instead of asking "should I plot?", plot every bar and decide what value or colour to show. Here is the tested fix for the first example:
//@version=6
indicator("Conditional plot", overlay = true)
fast = ta.ema(close, 9)
plot(close > fast ? fast : na, "EMA 9 when above", color.orange, 2, plot.style_linebr)
plotshape(ta.crossover(close, fast), "Cross up", shape.triangleup, location.belowbar, color.green)
Three things changed:
plot()moved to the left margin, so it is in global scope.- The condition moved into the value:
close > fast ? fast : na. When the condition is false, the value isna, which means nothing to plot on that bar. - A
plotshape()marks the crossover. For a marker on certain bars,plotshape()orplotchar()with a true/false condition is the usual tool. In the tested code it sits at the top level next toplot().
Switch the colour instead of the value
If you want the line to keep its values but disappear on some bars, make the colour conditional and use na as the colour:
//@version=6
indicator("Colour switch", overlay = true)
fast = ta.ema(close, 9)
plot(fast, "EMA 9", close > fast ? color.orange : na, 2)
Use labels or lines when you need a drawing inside a block
Drawing objects follow a different rule. label.new() and line.new() can be called anywhere, including inside an if. So when you want a text tag on a crossover, it is fine to create it inside the condition, while plotchar() stays at the top:
//@version=6
indicator("Labels on crosses", overlay = true)
fast = ta.ema(close, 9)
plotchar(ta.crossunder(close, fast), "Cross down", "x", location.abovebar, color.red)
if ta.crossover(close, fast)
label.new(bar_index, low, "Up", style = label.style_label_up, color = color.green)
For the helper function case, have the function return a value and plot that value outside it: e = myEma(9) at the top level, then plot(e).
What SuperCharting's Script Editor shows
SuperCharting's engine is more lenient here and runs this code. The broken example above, with plot() inside the if, compiles and runs in the Script Editor without an error. If the script must also work on TradingView, fix it the way shown above, because TradingView will reject it.
To check your own version:
- Open the Script Editor with Ctrl + E.
- Paste the script into the code area.
- Read the console, then press Add to chart.
Since the editor does not stop on this mistake, look for indented plot, plotshape or plotchar lines yourself before you share a script that others will run on TradingView. The Pine Script code checker page explains the two checks the editor does run, and Pine Script v6 basics covers how blocks and indentation work.
Related errors
If you fix the plot by deleting it and leave nothing else that draws, TradingView will complain that the script must have at least one output function. If you move a variable into the if block to get the plot out, you may meet undeclared identifier instead, because the variable is no longer visible at the top level. And if the line you plot comes from a function that tries to change a global variable, see cannot modify global variable in function.
Frequently asked questions
Can I plot only when a condition is true?
Yes, by putting the condition in the value. plot(cond ? value : na) plots value on bars where cond is true and nothing on the others. The plot() call itself must stay at the top level.
How do I show a marker only on some bars?
Use plotshape() or plotchar() at the top level and give it the condition: plotshape(ta.crossover(close, fast), ...) marks the crossover bars. Both tested examples on this page keep these calls at the left margin.
Why can label.new() go inside an if block when plot() cannot?
Pine must know every plot when it compiles the script, and a plot inside a condition might or might not exist. Label and line objects have no such rule, so they can be created anywhere, including inside a block.
My script works in SuperCharting. Do I still need to change it?
Only if you want it to run on TradingView as well. SuperCharting's engine accepts plot() inside an if; TradingView does not.
TradingView and Pine Script are trademarks of TradingView, Inc. SuperCharting is independent and not affiliated with it.