Guide

The Pine Script Type System: Series vs Simple vs Const

If you have ever seen 'cannot call with arguments of type series' and had no idea what it meant, this is the article that fixes it. The type system is the thing that quietly breaks the most Pine Script code.

11 min read

Pine Script has two things that most languages combine into one. It has types, like int, float, bool, string, and color, which describe what kind of value you have. And it has qualifiers, which describe when that value is known. The qualifiers are the part nobody explains, and they are the source of the most confusing errors in the language.

When TradingView tells you it "cannot call function with arguments of type series", it is not talking about the type. A number is a number. It is talking about the qualifier: you passed a value that can change bar to bar into a slot that needs a value fixed up front. Understanding that one distinction turns a wall of cryptic errors into a short checklist. This builds directly on how the execution model works, so if series values are new to you, start there.

The four qualifiers, from most to least fixed

There are four qualifiers, and they form a hierarchy based on how early the value is known. At the most fixed end is const, a literal value written into your code like 14 or "RSI", known before the script even runs. Next is input, a value that comes from the settings panel and is fixed once the user picks it. Then simple, a value that is determined on the first bar and then never changes, like the symbol's tick size. At the loosest end is series, a value that can be different on every single bar, like close or a moving average.

QualifierKnown when?Example
constAt compile time100, "RSI", color.red
inputWhen settings loadinput.int(14)
simpleOn the first bar, then fixedsyminfo.mintick
seriesCan change every barclose, ta.sma(close, 20)

The hierarchy runs const, then input, then simple, then series, from most fixed to most variable. The rule that governs almost everything is this: a value with a more fixed qualifier can be used wherever a looser one is expected, but not the other way around. You can pass a const where a series is wanted, because a constant is trivially a series that happens to never change. You cannot pass a series where a simple is required, because the function needs to know the value up front and a series does not settle until the bars roll in.

Where this actually bites you

The classic example is the length argument of a built-in. Many functions accept a series int length, but some historically required a value that does not change across bars. The length of a lookback window, for instance, often needs to be known so Pine can size its history buffer. If you try to feed it a value that changes every bar, you get the type-qualifier error.

pine
//@version=6
indicator("Qualifier mismatch", overlay = true)

// This length changes every bar: it is a "series int"
dynamicLen = int(math.round(10 + 5 * math.sin(bar_index / 10.0)))

// Some functions reject a series length and want a simpler qualifier.
// The fix is usually to make the length an input or a constant.
lenInput = input.int(14, "Length")   // this is "input int", accepted widely

sma1 = ta.sma(close, lenInput)       // fine
// sma2 = ta.sma(close, dynamicLen)  // may error depending on the function

plot(sma1)

The practical takeaway: when a function complains about a series argument, the usual fix is to supply the value as an input or a literal constant instead of something you compute per bar. If you genuinely need the value to vary, you often have to restructure, for example by computing several fixed-length results and selecting between them.

PineScripter reads the type-qualifier error and applies the correct fix automatically

Function parameters define the contract

Every built-in function documents the qualifier it expects for each parameter. When you write your own functions, Pine infers the qualifiers from how you use the parameters inside the body. If you use a parameter in a way that only works for a fixed value, the function will reject a series argument at the call site, sometimes far from where the real problem is. Reading the qualifier in the error message, and matching it against what the function wants, is the fastest way to locate the mismatch.

How v6 tightened the rules

Pine Script v6, which landed in November 2024, made the type system stricter in a way that matters here. The headline change is strict booleans. In v5, a bool could quietly be na, an undefined value, and the language would treat it loosely. In v6, booleans used in conditions are expected to be genuinely true or false, so code that leaned on a na boolean behaving like false can now break. The fix is to be explicit, for example nz(myBool) or an explicit comparison, so the value is always a real boolean.

pine
//@version=6
indicator("Strict booleans in v6")

// A condition that could be na in v5 is now handled more strictly.
crossedUp = ta.crossover(close, ta.sma(close, 50))

// Guard values that might be na before using them in boolean logic
enoughBars = bar_index > 50
signal = enoughBars and crossedUp

plotshape(signal, style = shape.triangleup, location = location.belowbar)

The v6 tightening is a net positive. It surfaces bugs that used to hide until a live bar produced an na at the wrong moment. But if you paste v5 code, or code written by a generic AI trained mostly on older examples, the stricter rules are a common reason it fails to compile. Our guide to compile errors covers the other frequent causes.

A mental checklist for qualifier errors

When you hit a qualifier error, walk through three questions. First, which argument is it complaining about, and what qualifier does that function want. Second, where does your value's qualifier come from: is it a literal, an input, or something you compute per bar. Third, can you move the value to an earlier stage, usually by making it an input, or do you need to restructure the logic. Ninety percent of these errors resolve at question two, because the value was computed as a series when a fixed value would do.

Why generic AI struggles with this specifically

The qualifier system is close to invisible in Pine Script's surface syntax. You do not usually write series or simple yourself; the compiler infers them. A general model like ChatGPT has no feel for that inference, so it happily writes code that mixes qualifiers in ways that will not compile, and it cannot see the resulting TradingView error to correct itself. That is the copy-paste loop that trips up ChatGPT users: generate, paste, read the qualifier error, paste it back, wait for a full rewrite, repeat.

A tool built for Pine Script closes that loop. PineScripter has the v5 and v6 manuals as context, so it targets the right qualifiers up front, and when a type error does surface it reads the message and applies the fix without you translating anything. You can see how that works in how PineScripter works, or just try it free at PineScripter and paste a strategy that keeps throwing type errors. Either way, once you can read the qualifier in the message, this class of error stops being mysterious.


Disclaimer: PineScripter is a coding tool for Pine Script development. It does not provide financial advice and does not guarantee trading profits. Always backtest strategies thoroughly and understand the risks before live trading.