OS2xxx Names and types
Every OS2 code, raised when a script parses but its meaning does not work out, such as a name read before it exists, a name declared twice, or two values of types that do not fit together.
On this page
OS2xxx codes come from the checker, the check stage that runs after the file has been read and before the first bar. By then the text is a well-formed program, and what fails is its meaning: a name read before it is assigned or spelt differently from its assignment, the same name declared twice, a number where a condition belongs, [] on a value that keeps no history. Nothing has run yet, so these are still cheap to fix: the change is on the line reported, or on the line the message points to.
Two ideas explain most of this range. First, names follow the order of the file: a script runs top to bottom on every bar, so a name must be assigned above the line that reads it, and a name first assigned inside a block stays inside that block. Second, types never convert by themselves: a number is not a string and 0 is not false. When you mean a conversion you write it: text() turns a number into a string, toNumber() reads a number from a string, and a comparison such as count > 0 turns a number into a bool.
A script that gets names and types right
This study marks bars on any NSE or MCX instrument where volume jumps above a multiple of its recent average. Every name is assigned before it is read, every condition is a bool, and the number in the marker is turned into text with text().
version 1
study("Volume spike", overlay = false)
len = input(20, "Average length")
mult = input(2.0, "Spike multiple")
// Assigned at the top level, above every line that reads it.
avgVolume = sma(volume, len)
spike = volume > mult * avgVolume
plot(volume, "Volume", gray, style = "histogram")
plot(avgVolume, "Average volume", orange)
// A condition is a bool, and text is built with text().
if spike and not spike[1]
signal("Spike " + text(volume / avgVolume, 1) + "x")The rules it follows, and the code you get for breaking each one:
| Rule | Code when broken |
|---|---|
| A name is assigned above the line that reads it, in the same block or an enclosing one | OS2001 |
| One variable per name: no second declaration inside a function, and no reuse of a built-in name | OS2002 |
| A name keeps the type of its first value, and types never mix on their own | OS2003 |
A condition is a bool | OS2011 |
[] reads the history of a series (a value with one entry per bar): a built-in series, a top-level name, or a call that returns a series | OS2004 |
One study() or strategy() declaration per file | OS2007, OS2008 |
Names and scope
A name is declared by its first assignment. At the top level it belongs to the whole file from that line on. Inside an if, a loop, a switch arm or a function body it belongs to that block. Assigning inside an if or a loop to a name that already exists above updates that name, so there is only ever one variable with a given name. See Variables and scope.
OS2001 Name is not defined here
What it means
The name is not known on the line that reads it. There are three usual causes. It is misspelt, and the fix suggests the closest name the compiler knows, as with lenght for len. It is assigned further down the file, and since the script runs top to bottom on every bar, a line cannot read a name that has not been assigned yet. Or it was first assigned inside an if, a loop or a function and is read outside it, where it does not exist: assign it at the top level first, even as none, and let the block update it.
A prefix in front of a library function also lands here, as in ta.ema(close, 9), because the whole dotted name is unknown: everyday functions are written bare, ema(close, 9). Your own functions are the one exception to the order rule: an fn may be called on a line above its declaration.
How to fix it
Assign name above this line, move this line below its assignment, or correct the spelling to suggestion.
Before
plot(spread, "Spread", aqua)
spread = high - lowAfter
spread = high - low
plot(spread, "Spread", aqua)OS2002 The name already exists in an enclosing scope
What it means
OpenScript never has two variables with one name. A function body can read a name from the file but not declare one of its own with the same name, so len = 9 inside a function, when the file already has a len, is refused, and so is a parameter called len. Built-in names such as close, high, ema, aqua and plot count as declared already: close = 5, ema = 9 or a parameter called high all land here, and the message then gives the earlier line as built-in.
Rename the new name. Inside an if or a loop, assigning to a name from above is not this error: it updates that name, which is usually what you wanted.
How to fix it
Rename this one, or drop the inner declaration and let the assignment update the name at line line.
Before
len = 20
fn smooth(src) =>
len = 9
sma(src, len)After
len = 20
fn smooth(src) =>
inner = 9
sma(src, inner)OS2006 Assignment to a loop variable
What it means
A for loop owns its variable: the counter in for i = 0 to 9, or the element in for price in prices. The body may read it but not assign to it, because a loop whose counter the body can move no longer runs the number of times its header says. To leave the loop early, use break. To work with a changed value, copy it into a name of your own first.
How to fix it
Use break to leave early, or keep a separate name for the value the body changes.
Before
for i = 0 to 9
if close[i] > hi
i = 9After
for i = 0 to 9
if close[i] > hi
breakOS2009 Unknown member of a namespace
What it means
A namespace such as bar, chart, session, date, str, math, pos, order or draw holds a fixed set of members, and the one written is not among them. It is a typo or a member of a different namespace. The fix names the closest member, which is right for a small slip (session.isFirst suggests isFirstBar) and only a guess for a bigger one (chart.lot suggests chart.now, when the member wanted is chart.lotSize). The reference lists every member of every namespace.
How to fix it
Use one of namespace's members; suggestion is the closest match to what was written.
Before
plot(bar.idx, "Bar", aqua)After
plot(bar.index, "Bar", aqua)OS2010 This name is not a function
What it means
Built-in values such as volume, high and bar.index are read bare, without brackets. An argument list after one usually means a function was remembered under the wrong name: volume(20) for the 20-bar average volume is sma(volume, 20). Remove the brackets to read the value, or call the function you meant. The function the fix names is only the closest spelling to the value you wrote, so it is often unrelated: for volume(20) the console suggests blue. Look up the function you meant in the reference.
How to fix it
Remove the argument list to read the value, or call the function that was meant: suggestion.
Before
v = volume(20)After
v = sma(volume, 20)OS2020 Name is planned, not implemented
What it means
The name is part of the language and is not implemented in this release. It is spelt correctly, and no line above it would help. The reference marks such names as Planned. Examples in version 0.5.0 include kama(), session.isOpen and the multi-leg leg.fixed().
Compute the value from functions that exist today, or take the line out until a release implements it. Do not swap in a function with a similar name just because it compiles: it computes something else, and a plot that quietly changes meaning is worse than one that refuses to compile.
How to fix it
Compute what name would give from names the library implements today, or take the line out until a version implements it. Do not reach for the nearest name that compiles: a neighbour computes something else, and a plot that quietly changes meaning is worse than one that refuses to compile.
Before
zScore = (close - sma(close, 20)) / stdev(close, 20)
plot(math.tanh(zScore), "Squashed", aqua)After
zScore = (close - sma(close, 20)) / stdev(close, 20)
doubled = exp(2 * zScore)
plot((doubled - 1) / (doubled + 1), "Squashed", aqua)Types
Every value has a type: number, string, bool, color, an array, or one of the object types. A name takes its type from its first definite value and keeps it. See Types and values.
OS2003 Types do not match
What it means
Two values whose types do not fit together meet in one expression. The language never converts on its own: "count: " + 5 is refused because + joins two strings or adds two numbers, never one of each, and 1 + true is refused because a bool is not a number. Convert explicitly: text() turns a number into text (text(x, 2) with two decimals), toNumber() reads a number from a string, and toBool() turns an absent value into false.
The same code covers a name whose type changes. len = 14 followed later by len = "fourteen" is refused, because len became a number on its first line. A first value of none fixes no type, which is how var stop = none can later hold a price. It also covers a plot handle used as a number: p = plot(close, "Close") names the plot itself, not its value, so p + 1 has nothing to add. Keep the value in a name of its own and plot that.
How to fix it
Convert explicitly: text(x) for a string, or text(x, decimals) to fix the decimals. Where no conversion applies, write the value in the type the line needs, or give the second value a name of its own. A plot, fill or level handle converts to nothing: leave it named at the top level, pass it to fill(), and use draw.line() or draw.box() where the script needs something it can keep.
Before
s = "count: " + 5After
s = "count: " + text(5)OS2011 A condition must be a bool
What it means
if, while, not, both sides of and and or, and the ? of a ternary need a bool, or an absent value, which takes the false branch. No rule turns a number or a string into true or false, so write the test you mean: hitCount > 0 for a count, mode != "" for a string, isNone() for absence. if volume is the same mistake; write if volume > 0.
This is the case of OS2003 for conditions, with a fix that names the test to write.
How to fix it
Write the test out: name > 0 for a count, isNone(name) for absence, name != "" for a string.
Before
if hitCount
signal("SEEN")After
if hitCount > 0
signal("SEEN")OS2012 The two arms of the ternary have different types
What it means
The two arms of condition ? a : b produce one value, so they must be the same type. none fits either arm, and it is how an arm says there is nothing here, as in plot(ready ? value : none, "Value"). Otherwise make both arms produce the same kind of value, for example two strings, or convert one arm with text() or toNumber().
How to fix it
Make both arms the same type with text() or toNumber(), or use none for the empty arm.
Before
label = up ? 1 : "down"After
label = up ? "up" : "down"OS2013 An array literal mixes types
What it means
An array holds elements of one type, which is what lets size(), sum(), avg() and sort() mean one thing. A literal such as ["RSI", 14, "EMA", 9] mixes strings and numbers, and it is usually two lists that belong side by side: keep one array of names and one of lengths, and index them together.
How to fix it
Make every element firstType, or keep two arrays and index them together.
Before
rows = ["RSI", 14, "EMA", 9]After
names = ["RSI", "EMA"]
lengths = [14, 9]History
OS2004 This value has no history
What it means
[1] reads the value a name had one bar ago, and the engine keeps that history only for values it records on every bar: built-in series such as close and volume, names assigned at the top level of the file, calls that return a series (so ema(close, 9)[1] works), and series parameters of your own functions. Everything else keeps no history: a name first assigned inside an if or a loop, a bracketed expression such as (close - open)[1], a plot handle, a drawing object, and a fixed fact about the instrument such as chart.lotSize.
Assign the value to a top-level name and read that name's history: body = close - open, then body[1]. See Bars and history.
How to fix it
If the value is a per-bar number computed inside a block or left as a temporary, assign it at the top level of the file and read the history of that top level name. If it is a declaration handle, a runtime object or a library fact that is not a series, no name gives it a history: assign what you want to look back at to a top level name of its own, and read that.
Before
if trending
body = close - open
plot(body[1], "Previous body", aqua)After
body = close - open
plot(trending ? body[1] : none, "Previous body", aqua)Arrays and annotations
An annotation states a type after a colon, as in var hits: array<number> = [] or fn band(src: series number). Annotations are optional; the compiler checks them when you write them.
OS2015 The element type of this empty array is unknown
What it means
An empty array literal, [], has no elements to take its type from. The compiler looks for an annotation, or for the first push(), unshift(), insert() or set() in the file that puts an element into the array, and uses that. With neither, it does not guess. Annotate the declaration, var hits: array<number> = [], or add the call that fills it.
How to fix it
Annotate the declaration, var hits: array
Before
var hits = []
plot(size(hits), "Hits", aqua)After
var hits: array<number> = []
plot(size(hits), "Hits", aqua)OS2016 Unknown type in an annotation
What it means
The types you can write in an annotation are number, string, bool, color, array<T> and the object types line, label, box, polyline and table, with series in front for a value that changes per bar. There is no int or float: a length, a bar count and a price are all number. plot, fill and level cannot be written in an annotation either, because a plot handle can never be stored, passed or returned.
How to fix it
Use number, string, bool, color, array
Before
fn band(src: series number, len: int = 20) =>
sma(src, len)After
fn band(src: series number, len: number = 20) =>
sma(src, len)OS2019 This type cannot be an array element
What it means
An array element is a number, a string, a bool, a color, or a line, label, box, polyline or table object. An array of arrays, an array of series and an array of plots are all refused. To keep several plots, declare each one at the top level with its own name. To keep several values per entry, keep one array per value and index them together. This is the case of OS2016 for array elements.
How to fix it
Use an element type an array holds: number, string, bool, color, line, label, box, polyline or table. A plot cannot be kept anywhere, so declare each plot at the top level and give it its own name.
Before
var edges: array<plot> = []
push(edges, plot(upper, "Upper", aqua))After
upperEdge = plot(upper, "Upper", aqua)
lowerEdge = plot(lower, "Lower", aqua)
fill(upperEdge, lowerEdge, color = fade(aqua, 88))Functions
OS2005 Recursive call
What it means
A function cannot call itself, directly or through other functions, and the message names the cycle, such as a calls b calls a. Each place in the file that calls a function keeps its own state for var and for stateful calls such as ema(), set up before the first bar, and a recursive call would need an unknown number of them. Rewrite the work as a for or while loop. In version 0.5.0 the console also shows OS6018 on the function's line, with a long technical message; it clears when the recursion does.
How to fix it
Rewrite it as a loop, or split the work into two functions that do not call each other.
Before
fn total(n) =>
if n <= 0
return 0
close[n] + total(n - 1)After
fn total(n) =>
runningTotal = 0.0
for i = 0 to n
runningTotal += close[i]
runningTotalOS2014 A function cannot be used as a value
What it means
In version 1 a function is not a value: you cannot assign ema to a name, keep it in an array or pass it to another function, as in sma(ema, 9). Call it with its arguments and use what it returns. To let the user choose between moving averages, pass a string input to ma(), which takes the kind of average as its third argument.
How to fix it
Call name with its arguments and use the value it returns.
Before
src = ema
plot(src, "EMA", aqua)After
src = ema(close, 9)
plot(src, "EMA", aqua)OS2017 A function with this name is already declared
What it means
A file has one function per name. Two fn declarations with the same name would make each call's meaning depend on its arguments, so the second is refused. Rename one of them, or merge the two by giving the extra parameter a default value: fn band(src, len = 20) => sma(src, len) covers both band(close) and band(close, 50).
How to fix it
Rename one of them, or give the one function a default argument that covers both uses.
Before
fn band(src) => sma(src, 20)
fn band(src, len) => sma(src, len)After
fn band(src, len = 20) => sma(src, len)OS2018 Duplicate parameter name
What it means
Every parameter of a function needs its own name, because the body refers to parameters by name and a named argument in a call picks one by name. Rename the repeated parameter.
How to fix it
Rename the second parameter, so every name in the list appears once.
Before
fn ratio(src, src) => src / src[1]After
fn ratio(src, len) => src / src[len]The declaration
Every script has exactly one declaration, study() or strategy(), and by convention it sits directly under version 1. It gives the chart the title, the pane and the settings it needs before the first bar. See Declarations.
OS2007 The file has no declaration
What it means
The file has no study() or strategy() line. Without one there is no title for the legend and no entry for the indicator list. Add study("Name") under version 1, or strategy("Name") if the script will place orders.
How to fix it
Add study("Name") as the first statement, or strategy("Name") if the file places orders.
Before
fast = ema(close, 9)
plot(fast, "Fast", aqua)After
study("EMA", overlay = true)
fast = ema(close, 9)
plot(fast, "Fast", aqua)OS2008 More than one declaration
What it means
The file declares twice. A strategy accepts every option a study does, so a file that seems to need both is a strategy: keep the strategy() line, move any options from the study() line onto it, and delete the study() line. See Strategies overview.
Related. Reading an error, Variables and scope, Types and values, Absent values, Bars and history, User functions, Collections, OS3xxx Arguments
How to fix it
Delete this declaration and move the options you wanted onto the one at line line.
Before
study("EMA cross", overlay = true)
strategy("EMA cross")After
strategy("EMA cross", overlay = true)