OS1xxx Syntax errors
Every OS1 code, raised when the text of a script cannot be read as a program, from characters the language does not use to indentation, brackets and statements written in the wrong shape.
On this page
Syntax errors are the first thing the compiler looks for. They come from the two stages that run before anything else: the lexer (lex), which reads the characters of your file into words, numbers and symbols, and the parser (parse), which reads those into statements and blocks. An OS1xxx code means the text itself is not a program yet, so no name has been looked up, no bar has run and nothing has been drawn. The fix is always local: the line reported, or the line where the bracket or block it names was opened.
Most syntax errors come from three places. Text copied from a web page, a chat message or a document brings invisible spaces and curly quotes with it. Operators typed out of habit, such as && or !, are spelled as words in OpenScript. And indentation is how the language marks a block, so a line one space out of place changes the structure.
What well-formed code looks like
This study follows every layout rule on this page. It marks the high of the NSE opening range, the first fifteen minutes from 09:15 to 09:30, and signals the bar whose close first moves above it. Paste it into a new script to have a known-good reference beside your own.
version 1
study("Opening range breakout", overlay = true)
// A comment runs from // to the end of its line.
var rangeHigh = none
inRange = session.isIn("0915-0930")
rangeStarts = inRange and not orElse(inRange[1], false)
// A block is the lines indented under its header, four spaces per level.
if rangeStarts
rangeHigh = high
else if inRange
rangeHigh = max(rangeHigh, high)
// An operator at the end of a line continues the statement on the next.
breakout = not isNone(rangeHigh) and close > rangeHigh and
close[1] <= rangeHigh[1]
plot(rangeHigh, "Range high", orange)
if breakout
signal("Breakout")The rules it follows, and the code you get for breaking each one:
| Rule | Code when broken |
|---|---|
version 1 is the first line that is not blank or a comment | OS1021 |
One statement per line, and no ; anywhere | OS1007, OS1018 |
| Indent blocks with spaces, the same amount on every line of a block | OS1002, OS1003 |
A header such as if has an indented body under it | OS1010 |
| A continued line is indented past the line its statement began on | OS1028 |
Comments start with // | OS1026, OS1001 |
Logic is written and, or and not | OS1001 |
| One comparison per expression | OS1008 |
Every ( and [ is closed by its own kind of bracket | OS1012, OS1013 |
Characters and literals
Outside strings and comments, the lexer accepts only plain ASCII letters and digits, the space, the newline and the language's own punctuation. Inside a string or a comment any character is fine, so "Target ₹" and // rupee target both work. When OS1001 refuses a character, its message names the replacement from this table:
| You wrote | Write instead |
|---|---|
! | not |
&& | and |
|| | or |
^ or ** | pow(a, b) |
++ | a += 1 |
{ or } | indentation, which is how a block is written |
| A no-break space, an em space or another wide space | a plain space |
| A tab between two words on a line | a plain space |
| A curly quotation mark, single or double | a straight quote |
| A letter with an accent in a name | the plain ASCII spelling |
#, $ or @ outside a colour | nothing: delete it, or move the text into a string |
OS1001 Unexpected character
What it means
You typed a character that the language does not use outside a string or a comment. Often you cannot see it: a no-break space or a curly quotation mark arrives with code copied from a web page, a chat message or a document, and it looks exactly like a normal space or quote. The rest are operators typed out of habit, such as !, &&, ||, ^, ** and ++, or braces around a block. The message quotes the character and names the replacement. For an invisible or unusual character it also gives the Unicode number, such as U+00A0, and for spaces, tabs and quotation marks a name such as "a no-break space". A tab at the start of a line is OS1002 instead.
When the character is invisible, delete the text around the reported column and type it again by hand. For a pasted string, retyping its two quotes is usually enough. A # typed to start a comment lands here too: comments start with //.
How to fix it
Delete the character or replace it with the plain ASCII spelling the message names: a plain space for a non-breaking space, a straight quote for a typographic one, not for !, and for &&, or for ||, pow(a, b) for ^.
Before
if !ready
signal("BUY")After
if not ready
signal("BUY")OS1027 Malformed colour literal
What it means
A # followed by hexadecimal digits is a colour, and it needs exactly six digits, as in #ff8800, or eight, where the last two set the transparency, as in #ff880080. The short forms #fff and #ff88 are not accepted, and neither is a character outside 0 to 9 and a to f (capitals A to F are fine). Because the colour is dropped from the line, the console usually shows OS1022 beside this error; correcting the colour clears both. If hex digits are not what you want, a named colour such as orange or rgb() says the same thing.
This is the case of OS1001 for colours. It has its own code because deleting the #, the advice OS1001 gives, would throw away a colour you nearly had right.
How to fix it
Give it six hexadecimal digits, or eight where the last two are the alpha byte. A named colour or rgb(r, g, b) says the same thing without the digits.
Before
plot(close, "Close", #ff88)After
plot(close, "Close", #ff8800)OS1029 A name written against a number
What it means
A name cannot start with a digit, and a number cannot have letters attached to it. The usual causes are a variable called something like 2fast, a unit typed after a quantity (10k, 5m), a binary or octal literal (0b1011, 0o17), and an underscore at the end of a number (1_000_). Numbers are written in decimal, such as 1_000_000 or 2.5e-4, or in hexadecimal with 0x, and an underscore may only sit between two digits.
Rename the variable so it starts with a letter (fast2), and write quantities in full: 10000, not 10k. When you meant a number followed by a name, put an operator between them.
How to fix it
Write the value in a form the language has: a decimal literal, or 0x and hexadecimal digits. There is no binary form and no octal form, and an underscore separates digit groups only where a digit follows it. Where a number and a name were meant as two things, put an operator between them.
Before
mask = 0b1011After
mask = 0x0bOS1004 Unterminated string literal
What it means
A string opens and closes on the same line, with the same kind of quote: "BUY" or 'BUY'. This error is reported at the opening quote when the line ends before a matching one, which almost always means the closing quote is missing. The unclosed string also swallows the ) of the call it sits in, so OS1012 usually appears beside it and goes away when the quote is added.
A string cannot span lines. To build a long message, close each piece and join them with +, ending the line with the + so the statement continues.
How to fix it
Close the string with a matching quote before the end of the line, and join text across lines with + and a continuation.
Before
signal("BUY)After
signal("BUY")OS1005 Unknown escape sequence
What it means
Inside a string, a backslash starts an escape sequence: \n for a new line, \t for a tab, \r, \0, \\ for a backslash, \" and \' for quotes, and \u followed by exactly four hexadecimal digits for any character, such as \u20b9 for the rupee sign. A backslash followed by anything else is refused rather than guessed at. It most often comes from a file path or a pattern pasted with single backslashes: write each backslash as \\.
How to fix it
Double the backslash to write one literally, or use one of the escapes the language defines.
Before
path = "C:\data\bars"After
path = "C:\\data\\bars"OS1026 Block comment
What it means
OpenScript has line comments only: // starts one and it runs to the end of the line. /* and */ are not comment markers, so the compiler reports them where they sit instead of letting an unclosed comment hide the rest of the file. To comment out several lines, put // at the start of each one.
How to fix it
Write // instead, and give every line of a commented region its own //, which every editor does with one keystroke.
Before
lookback = 14 /* bars */After
lookback = 14 // barsOS1007 Semicolon
What it means
A statement ends at the end of its line, so there is nothing for a semicolon to do, and a semicolon at the end of a line is refused as well as one between two statements. Delete it, and give each statement a line of its own.
How to fix it
Delete the; and put the second statement on its own line.
Before
fast = ema(close, 9); slow = ema(close, 21)After
fast = ema(close, 9)
slow = ema(close, 21)Indentation and blocks
A block is the lines indented under a header: if, else, for, while, switch, case, default, or a function whose body starts on the next line. The block ends at the first line indented as far as its header, or less. Indent with spaces, four per level by convention. Blank lines and lines that hold only a comment never affect a block, so they may sit at any indentation.
OS1002 Tab in indentation
What it means
The line is indented with a tab. A tab is drawn at a different width in every editor, so a block marked with tabs could mean one thing on your screen and another on someone else's, and the language accepts spaces only. In the /trading editor the Tab key moves the focus out of the editor rather than typing anything, so a tab almost always arrives in pasted code. Replace each leading tab with four spaces.
How to fix it
Replace the leading tabs with spaces. Four spaces per level is the convention and the formatter's output.
Before
if close > open
signal("UP")After
if close > open
signal("UP")OS1003 Indentation does not match this block
What it means
Every line of one block must start at exactly the same column, and a single space more or less counts. The message says how many spaces this line has, how many its block has, and which line opened the block. Line it up with the lines above it to keep it in the block, or with the header to end the block there.
A continued statement, one that carries on from the line above because of an open bracket or a trailing operator, follows a different rule: see OS1028.
How to fix it
Indent this line to expected spaces to keep it in the block, or to line's own indentation to end the block here.
Before
if trending
body = close - open
wick = high - lowAfter
if trending
body = close - open
wick = high - lowOS1028 A continuation line is not indented past its statement
What it means
A statement continues onto the next line when a bracket is still open, when the line ends with an operator, a comma, ?, : or =, or when it ends with a backslash. The continued line must be indented further than the line the statement began on, so that nobody reading the file can mistake it for a new statement. Indent it; any amount deeper than the first line works, and lining it up under the opening bracket reads well.
This is the case of OS1003 for continued lines. It has its own code because a continuation opens no block, so the block rule's message would describe a block that is not there.
How to fix it
Indent this line further than the statement spaces on line line. Four more is the convention and the formatter's output.
Before
total = ema(close, 9) +
ema(close, 21)After
total = ema(close, 9) +
ema(close, 21)OS1010 Block header with no body
What it means
A header line promises an indented body, and the next line is not indented more deeply. This is nearly always a body that lost its indentation when it was pasted. Indent the body under the header.
if, else, the loops, case and default have no one-line form, so even a body of one statement goes on its own indented line. A function can be written on one line by putting its body after =>: fn barRange() => high - low. Blank and comment lines do not count as a body.
How to fix it
Indent the body under the header, or delete the header line if the body is genuinely empty.
Before
if crossUp(fast, slow)
signal("BUY")After
if crossUp(fast, slow)
signal("BUY")OS1016 else does not follow an if
What it means
An else belongs to the if at exactly its own indentation. At any other indentation there is no if for it to pair with, and the compiler does not guess which one you meant. Line the else up with its if. An else if is written as two words on one line and is not indented further than the if.
An else with no if above it at all, such as one written after a for block, is reported the same way. When the else is indented by a stray space or two, OS1003 usually appears on the same line; lining it up clears both.
How to fix it
Line the else up with its if, at expected spaces.
Before
if trending
signal("BUY")
else
signal("WAIT")After
if trending
signal("BUY")
else
signal("WAIT")Brackets and expressions
OS1012 Bracket is never closed
What it means
An open ( or [ carries the statement onto the following lines, so when its closer is missing the compiler reads everything after it as part of one long statement. The error is reported at the opening bracket, which is where to look. It usually brings a crowd of other errors from the lines below, such as a continuation that is not indented or a missing comma; add the closer and they go with it. Reading an error shows one missing bracket producing six diagnostics.
How to fix it
Add the matching closer at the end of the argument list on line line.
Before
plot(ema(close, 9), "EMA", aquaAfter
plot(ema(close, 9), "EMA", aqua)OS1013 Mismatched closing bracket
What it means
A call closes with ), and a history index or an array closes with ]. This error means a bracket was closed with the other kind, such as sum(values] or close[1). The message names the bracket it found, the one it expected and the line the opener is on. Change the closer to match its opener.
How to fix it
Change found to expected, which is what closes the opener opened at line line.
Before
total = sum(closes]After
total = sum(closes)OS1014 Missing comma between arguments
What it means
Two values sit side by side inside a call with no comma between them. It usually comes from editing a call: a comma deleted by accident, as in plot(ema(close, 9) "EMA", aqua), or a named argument added without one, as in plot(close, "C" color = aqua). Put the comma back. The compiler reports it rather than guessing where the comma should go.
How to fix it
Put a comma between the two arguments.
Before
plot(ema(close, 9) "EMA", aqua)After
plot(ema(close, 9), "EMA", aqua)OS1022 Expression expected
What it means
A line ends with something that needs more after it (an operator, a comma, = or an opening bracket) and nothing usable follows. It is usually a half-finished edit, or a stray + or , left at the end of a line. Supply the missing value, or delete the trailing symbol.
It also appears beside another error on the same line when that error removed part of the expression, as with a malformed colour (OS1027). Fix the other error first.
How to fix it
Supply the missing operand, or delete the trailing token.
Before
len = input(14, "Length") +After
len = input(14, "Length")OS1015 Ternary with no second arm
What it means
The conditional operator, condition ? a : b, always produces a value, so it needs both of its arms. A one-armed version is usually a plot meant to draw on some bars only. Use none for the arm that should draw nothing: plot(ready ? value : none, "Value", aqua). A plot draws a gap wherever its value is none.
How to fix it
Give the ternary both arms, and use none for the arm that should draw nothing.
Before
plot(ready ? value, "Value", aqua)After
plot(ready ? value : none, "Value", aqua)OS1008 Chained comparison
What it means
30 < r < 70 reads naturally, but it can be read two ways, and a language that places orders does not guess. An expression holds at most one comparison, and that applies to == and != as much as to < and >. Split it with and, writing the middle value twice: 30 < r and r < 70.
The console usually shows OS2003 on the same line as well, because the first comparison produces a bool and the second then compares that bool with a number. Splitting the comparison clears both.
How to fix it
Split it with and, naming the middle value twice: a < b and b < c.
Before
if 30 < r < 70
zone = "mid"After
if 30 < r and r < 70
zone = "mid"OS1018 More than one statement on a line
What it means
The compiler finished reading a statement and found more on the same line. Either an operator is missing between two values (x = close open), there is one closing bracket too many (ema(close, 9))), or two statements share a line. Add the operator you meant, delete the extra bracket, or move the second statement to its own line.
How to fix it
Put token and what follows it on its own line, or supply the operator that was meant to join them.
Before
fast = ema(close, 9) slow = ema(close, 21)After
fast = ema(close, 9)
slow = ema(close, 21)OS1006 Assignment used as a condition
What it means
= stores a value and == compares two. A condition needs a comparison, so if len = 14 is refused instead of quietly storing 14 and treating the test as true. The same applies to a while condition. Write ==, or, if you did mean to store a value, do it on its own line above the if.
How to fix it
Write == to compare, or move the assignment to its own line above the if.
Before
if len = 14
signal("DEFAULT")After
if len == 14
signal("DEFAULT")Statements and names
OS1009 break or continue outside a loop
What it means
break leaves the innermost for or while loop, and continue skips to its next pass. Outside a loop body there is nothing for either to act on. To leave a function early, use return. To skip some work on some bars, put that work under an if; plots stay at the top level and take none on the bars they should skip.
How to fix it
Move it inside the loop body, or write return to leave a function early.
Before
fn firstAbove(values, mark) =>
if size(values) == 0
break
values[0]After
fn firstAbove(values, mark) =>
if size(values) == 0
return none
values[0]OS1011 var with no initial value
What it means
var declares a value that keeps its content from one bar to the next, and its starting value is part of the declaration, so no bar can ever read it empty by accident. Write var total = 0 to start from zero, or var runningHigh = none to start with no value and fill it on a later bar. See Persistence.
How to fix it
Give it a starting value; var name = none is the empty start.
Before
var runningHigh
if high > orElse(runningHigh, high)
runningHigh = highAfter
var runningHigh = none
if isNone(runningHigh) or high > runningHigh
runningHigh = highOS1017 case or default in the wrong place
What it means
case and default are the arms of a switch and exist only inside one, indented under it. default catches everything the cases above it did not, so it must be the last arm: a case after it could never run. Move the arms under their switch, with default at the bottom.
How to fix it
Move the arm inside the switch block, and put default after every case.
Before
switch method
default
len = 14
case "fast"
len = 9After
switch method
case "fast"
len = 9
default
len = 14OS1019 Reserved word used as a name
What it means
Reserved words belong to the language and cannot name a variable, a function or a function parameter. The ones people reach for most often are color, step, type, in and number. A few, such as type, map and import, are reserved for features planned for later versions, so that adding those features cannot break a script written today. The fix suggests a name that keeps your meaning, such as colorValue. The full list is on Keywords.
A named argument label is not a variable, so plot(x, "X", color = aqua) is fine. Writing bool(x) or number(s) to convert a value lands here too, because the conversions are toBool() and toNumber().
How to fix it
Rename it; suggestion keeps the meaning and is not reserved.
Before
type = input("fast", "Mode", options = ["fast", "slow"])After
mode = input("fast", "Mode", options = ["fast", "slow"])OS1020 Incomplete for header
What it means
A for loop has two forms and no others. A counted loop names a start and an end, for i = 0 to 9, optionally followed by step, and runs with both ends included. A loop over an array names the array, for price in prices. A comma between the bounds, or a header with no to, is this error. See Control flow.
How to fix it
Write for i = 0 to size(values) - 1 for a counted loop, or for v in values to visit elements.
Before
for i = 0, 9
total += close[i]After
for i = 0 to 9
total += close[i]OS1021 The version declaration is not first
What it means
version 1 must be the first line of the file, above the study() or strategy() declaration. Only blank lines and comments may come before it. The version is read before anything else so that the script is always compiled by the right version of the language. Move the line to the top.
How to fix it
Move the version line to the top of the file, above the study or strategy declaration.
Before
study("EMA cross")
version 1After
version 1
study("EMA cross")OS1023 A function declared inside a block
What it means
Functions are declared at the top level of the file, never inside an if, a loop, a switch arm or another function. Move the whole fn declaration out to the top level and call it from inside the block. A function may be called on a line above its declaration, so it can sit anywhere at the top level. See User functions.
How to fix it
Move the whole declaration out to the top level of the file, and call name from inside the block.
Before
if trending
fn smoothed(src) => sma(src, 9)
plot(smoothed(close), "Smooth", aqua)After
fn smoothed(src) => sma(src, 9)
smooth = smoothed(close)
plot(trending ? smooth : none, "Smooth", aqua)OS1024 Assignment to an indexed element
What it means
There is no assignment into brackets. On an array, change an element with set(): set(prices, 0, close). On a series such as close, [1] reads a bar the engine has already computed, and a past bar can never be rewritten. If you want a value of your own, assign it to a plain name.
How to fix it
Change an array element with set(name, i, v), or assign to a plain name: the past of a series is computed and never written.
Before
var prices = [0.0]
prices[0] = closeAfter
var prices = [0.0]
set(prices, 0, close)OS1025 Assignment to a member
What it means
A dot reads a member of a namespace such as chart, bar or session, and every member is a fact supplied by the library, the instrument or the position. A script cannot write to any of them, and version 1 has no user-defined records whose fields you could set. Assign the value to a plain name of your own: tick = 0.05, not chart.tickSize = 0.05. When the member does not exist either, OS2009 appears beside this error, as it does for the example below: chart has a tickSize member, not tickStep.
Related. Reading an error, Script structure, Keywords, Operators, Control flow, OS2xxx Names and types
How to fix it
Assign to a plain name. Version 1 has no member assignment: a dot reads a member, and the members a script can reach are facts and functions the library and the host supply.
Before
chart.tickStep = 0.05
plot(close + chart.tickStep, "Stepped", aqua)After
tickStep = 0.05
plot(close + tickStep, "Stepped", aqua)