Pine Script syntax and types

Does a Pine Script switch Need a Default Branch?

A default branch is optional for ordinary Pine Script v5 switch expressions. Write it as the final => branch with no condition before the arrow. Without a match, a numeric result is na. In v6, an unmatched bool result is false, and a switch returning a unique parameter type such as plot.style_line requires a default branch. Check the result type before deciding whether a missing default is an error.

Review a Switch Error with AI

Default syntax and the two switch forms

Use switch mode to match a value, or switch on its own line to evaluate boolean conditions in order. Only the first matching branch executes. Its final expression is the result, so break is unnecessary. The complete v6 script below selects a price and then a color. With mode set to Off, the default returns float(na), intentionally hiding the plot.

Complete v6 indicator: value matching and condition matchingpinescript
//@version=6
indicator("Switch default syntax", overlay=true)

mode = input.string("Close", "Source", options=["Close", "Open", "Off"])
price = switch mode
    "Close" => close
    "Open" => open
    => float(na)

lineColor = switch
    close > open => color.green
    close < open => color.red
    => color.gray

plot(price, "Selected source", color=lineColor)

No matching branch: v5 and v6 behavior

The version annotation matters when a switch has no default. Numeric na is still a missing value in v6, but bool no longer has a third state. This v5 example leaves Off unmatched and displays its boolean na state as -1. The table distinguishes an ordinary omitted fallback from the v6 unique-type restriction.

Result or usePine v5Pine v6
Unmatched int or float resultnana
Unmatched bool resultnafalse
switch returning plot.style_* without a defaultAllowed; plot style can fall back when naCompilation error, even if all input options are listed
Standalone switch used for side effectsNo matching branch means no branch actionNo matching branch means no branch action
Complete v5 indicator: Off produces -1 because selected is napinescript
//@version=5
indicator("Unmatched boolean in v5")
mode = input.string("Off", "Mode", options=["On", "Off"])
bool selected = switch mode
    "On" => true

state = na(selected) ? -1 : selected ? 1 : 0
plot(state, "1 = true, 0 = false, -1 = na")

Migrating an unmatched boolean to v6

Do not carry na(selected), nz(selected), or fixnan(selected) into v6 when selected is bool. Those functions no longer accept boolean arguments. Here Off becomes false, plotted as 0. If Off must mean unknown rather than false, represent that state explicitly instead of relying on a boolean na.

Complete v6 indicator: the same unmatched case produces falsepinescript
//@version=6
indicator("Unmatched boolean in v6")
mode = input.string("Off", "Mode", options=["On", "Off"])
bool selected = switch mode
    "On" => true

plot(selected ? 1 : 0, "1 = true, 0 = false")

The v6 case where a default really is required

plot.style_line and plot.style_columns have the unique plot_style type. In v6, a switch that returns this type needs a default, even when its cases cover the input options. The example supplies plot.style_line as the final branch. Remove that branch to reproduce the missing-default compilation problem; leave it in the working script.

Complete v6 indicator: default for a unique plot style typepinescript
//@version=6
indicator("Switch plot style fallback")
mode = input.string("Line", "Style", options=["Line", "Columns"])
selectedStyle = switch mode
    "Line" => plot.style_line
    "Columns" => plot.style_columns
    => plot.style_line

plot(close, "Close", style=selectedStyle)

Return types, multiline blocks, and tuples

When you assign a switch result, branch results must have compatible types. Numeric int values can widen to float; a string cannot become a price. A branch may declare local variables before returning its final expression. Tuples can contain different types, but every branch must return the same number of items with compatible types in corresponding positions. The example returns a float and a color together.

  • A numeric branch ending in "Off" is a type mismatch. Use float(na) for a missing numeric value, or keep the status text in a separate variable.
  • Write [value, tint] = switch to declare tuple results. Do not put type keywords inside the tuple declaration.
  • Tuple items share a qualifier. Combining a series price and an integer length can make the length series int, which ta.ema() does not accept.
Complete v6 indicator: local calculations return a float/color tuplepinescript
//@version=6
indicator("Switch tuple return", overlay=true)
mode = input.string("Midpoint", "Source", options=["Midpoint", "Close", "Off"])

[value, tint] = switch mode
    "Midpoint" =>
        float midpoint = (high + low) / 2.0
        [midpoint, color.blue]
    "Close" => [close, color.orange]
    => [float(na), color.gray]

plot(value, "Selected value", color=tint)

Scope: use := to update an existing variable

Each branch is a local scope. Declaring a same-named variable with = inside it shadows the outer variable; it does not update that variable. Use := for reassignment. Ordinary declarations run whenever their scope executes; var initializes on the first execution of its scope. Here direction persists with var, and the fallback resets it to zero on a doji bar. Without that fallback, a doji would preserve its previous value.

Complete v6 indicator: standalone switch changes persistent statepinescript
//@version=6
indicator("Switch reassignment")
var int direction = 0

switch
    close > open => direction := 1
    close < open => direction := -1
    => direction := 0

plot(direction, "Bar direction")

Diagnose the error before adding a fallback

These are diagnostic categories, not guaranteed compiler message wording. Fix the constraint named by the error, then compile the entire script. Syntax validation does not check whether a chosen fallback matches your trading rules. The examples on this page demonstrate language behavior, not a trading strategy.

SymptomCause to inspectRepair
Default branch required after a v6 migrationThe switch returns a unique type such as plot_styleAdd => plot.style_line or another valid value of that type
Branch return types do not matchA numeric result shares a switch with text or colorReturn compatible types, or use a consistent tuple such as [price, color]
Cannot use a plotting call in local scopeplot() sits inside a switch branchReturn the selected value and call plot() at global scope
Outer variable stays unchangedA branch declares a local variable with =Use := to update the existing variable
History-dependent calculation warns or behaves inconsistentlyA changing condition skips calls such as ta.crossover()Compute the series on every bar before selecting a branch
An indicator has missing values or an invalid lengthThe selected branch returns na or an invalid numeric parameterCheck the actual value; a default cannot repair a matched branch result
Where Pineify fits

Pine Script AI Coding Agent

Bring the complete script, its version, the compiler message, and the intended result for each mode to Pineify's AI Coding Agent. Ask for a branch or type fix, then review the generated code and test each input mode in TradingView.

Review a Switch Error with AI

Frequently asked questions

Programming examples for education. Compile your complete script and check each mode on a chart before using it in a trading system.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.