Common errors
The messages a wrun indicator author meets in the chart, each with its cause and its fix, in the order they arrive: the checks the editor runs on your code (declarations, lint, the sheet, the compiler, the module), then what a Run reports, then what the chart itself says.
Every heading is the text the editor prints, so a browser find on the message you got lands on its fix.
If your indicator ran but drew nothing, the problem is probably not an error at all. Skip to Ran but blank at the end.
Where errors show
- In the editor's Console. The editor checks your code as you type, and Run reuses those checks before it runs anything. Each problem is a row in the Console with its line number, its stage in brackets (
declarations,lint,metadata,validate), and the message; a compiler row carries the compiler's message and a hint that links to these docs. The same text shows as a squiggle under the span, and clicking a row jumps to its line. The status bar counts errors and warnings (its tooltip reads Open Problems) and opens the Console, and a blocked Run says "Cannot run: 2 error(s) must be fixed first." - After a Run. What the run itself finds prints as a
computerow with a "Fix:" line, next to the indicator's debug log (Debugging). - On the chart. An overlay whose run fails keeps its last good drawing; its legend shows a Could not load chip with the message and a Retry. An overlay that never drew anything also raises a one-time toast that starts "Indicator could not load:".
The checks are staged, so one problem hides the ones behind it: a declaration error stops the build before the sheet is checked, and a sheet error stops it before the compiler runs. Declaration errors arrive together, one row per finding, each on the line of the declaration it names.
option 'top' takes an output handle, not a string literal
Symptom: the declarations stage refuses a box(...) or segment(...) line with option 'top' takes an output handle, not a string literal (bind a handle with a top-level const h = output(...) and pass h).
Cause: a box or segment coordinate is the value output(...) returned, not the output's name. box("band", { top: "hi", ... }) passes a string where a handle goes.
Fix: bind the output to a top-level const and pass the const. The same rule covers bottom, yFrom, yTo, when, and an output-valued from / to:
param("period", 20, { min: 1, max: 200 });
output("sma", line, overlay);
// Bind each coordinate output to a const: the box names the handle, never the string.
const hi = output("hi", none);
const lo = output("lo", none);
box("band", { top: hi, bottom: lo, color: "#38bdf8", opacity: 0.15, borderWidth: 0 });
let sma = new Sma(20);
function onStart(): void {
sma = new Sma(i32(p_period()));
}
function onBar(): void {
const value = sma.update(bar.close());
out_sma(value);
out_hi(value * 1.01);
out_lo(value * 0.99);
}segment 'ray' option 'yTo' references 'top', which is not an output handle
Symptom: segment 'ray' option 'yTo' references 'top', which is not an output handle; bind the output first (const top = output("...", ...)) and pass that const.
Cause: the identifier you passed is a variable, but not one bound to an output(...) call.
Fix: bind it with const, let, or var at the top level (the binding may sit below the shape that uses it). The sheet records the output's name, never the handle.
output(...) declarations must be top-level statements
Symptom: output(...) declarations must be top-level statements, not inside a function, class, or expression (or the same for param, input, box, segment, render.text, and the rest).
Cause: declarations are read from the text without running it, so one inside onStart(), inside an if, or inside a class is invisible to the sheet and refused.
Fix: move the declaration to the top level of the file. Declarations are static: they cannot depend on a param or a condition.
param options accept only { required, min, max, description }, not 'step'
Symptom: the family's option list, followed by the option you wrote. On a typed setting the list is longer: param.int options accept only { required, min, max, description, label, step, group, row, hint, when, hide, slider, unit, unit_default, confirm }, not 'tooltip'.
Cause: every family lists its options in the message. Plain param(...) is the number field and keeps its four keys: it takes any value inside min..max and the settings dialog labels its row with description. The dialog's words (label, step, group, row, hint, when, hide, slider, unit, unit_default, confirm, and tz on a session) belong to the typed settings, param.int(...), param.bool(...) and the rest. A tooltip is hint, and there is no constraints object. A number-field key on a kind that is not a number field is refused by name too: param.bool 'x' takes no min option (its value is not a number field).
Fix: declare the setting with the kind that takes the option (param.int("length", 20, { min: 5, max: 500, step: 5 })), or drop the option. The option list per kind is on Options on a setting, the full grammar in Declarations and the sheet.
param 'symbol' uses a reserved name
Symptom: param 'symbol' uses a reserved name (the chart keeps symbol, exchange, interval, transformations, ticksPerBar, currency, runMode, devViewerTier, ... beside script settings, so a param under that name would be read as the chart's own); rename it, or param '__style__x' uses the reserved prefix __style__ (the chart's own style rows); rename it, or param.range 'band' derives param 'band_lo', which is already declared; rename one.
Cause: a setting's name is a key the chart saves beside the overlay's own keys, so the chart's own names and its Style rows' prefix are off limits; a range, list, session, unit menu or market.* call also derives names of its own (band_lo, levels_n, rth_tz, offset_unit, market_tick_size), which another setting cannot take.
Fix: rename the setting. Every other name is free, smooth, width and opacity included; the reserved list is on What the build checks.
output 'h' color references "@k", which is not a param.color
Symptom: output 'h' color references "@k", which is not a param.color, output 'h' color references "@nope", which names no declared param (a param.color), input 'c2' interval references "@k", which is not a param.timeframe, or output 'h' binds a param to its colour or line style, but the output is data-only (plot none): there is nothing to paint.
Cause: a string that starts with @ names a setting, and the spot decides the kind: color and a colors entry take a param.color, line_style a param.choice over solid, dashed, dotted, an input's interval a param.timeframe, its symbol a param.symbol. A none output draws nothing, so there is nothing for a color to paint.
Fix: declare the setting with the kind the spot needs and name it after the @, or write the literal.
duplicate output name 'sma'
Symptom: duplicate output name 'sma', duplicate param name, duplicate input name, duplicate box name, or duplicate render declaration name.
Cause: names are unique per family, and shapes share one namespace with outputs (below).
Fix: rename one of them.
expected a string literal
Symptom: expected a string literal, expected a numeric literal, option 'from' takes an output handle or a bar offset literal, not a string literal, or option 'panel' takes "overlay" or "lower" (a string literal), not 'price'.
Cause: a name built from a variable, a default computed from an expression, a bar offset spelled as a string, or a panel outside the two names. The extractor reads literals only, because the code never runs while it is checked.
Fix: use literals: param("period", 20, ...), from: -4, panel: "lower".
This indicator declares nothing
Symptom: This indicator declares nothing. Add param(...), input(...), and output(...) statements (imported from ./sdk/declare) at the top level of the source; the metadata sheet is derived from them.
Cause: the editor builds the sheet from your declarations, and there are none: an empty tab, code with no param / input / output statement and no onBar(), or a file with onBar() that also exports one of init, state, finalize or reset (that one export makes it a file of the four functions, whose declarations need their import lines). A file with onBar() and no declaration is told it needs an output instead (below).
Fix: start from New indicator or a template in the editor's Explorer, keep the //@lang=wrun-ts line first, and declare what the file reads and writes at the top level.
This looks like Pine Script, not an Indicator
Symptom: This looks like Pine Script, not an Indicator., on the first line of a paste.
Cause: the tab holds code from another language. A wrun indicator is TypeScript syntax compiled in your browser.
Fix: start from a template, keep the //@lang=wrun-ts line first, declare param(...) / output(...) (and an input(...) for anything beyond the chart's own candles), and write the bar's work in function onBar(): void.
code-first declarations need at least one input(...) and one output(...) statement
Symptom: code-first declarations need at least one input(...) and one output(...) statement (found 0 input(s), 1 output(s)), in a file with the four functions (init, state, finalize, reset).
Cause: such a file has no bar grid to walk without an input, and nothing to compute without an output. A file with onBar() needs no input line (the chart's own candles are its grid) and hears the next message instead when it has no output.
Fix: declare the primary input (input("close", ohlcv.close) is the usual one) and at least one output, even a none.
a file with onBar() needs at least one output(...) statement
Symptom: a file with onBar() needs at least one output(...) statement: declare what the Indicator draws, e.g. output("value", line, overlay), and write it in onBar() with out_value(...), on the file's first declaration (or on the onBar line when there is none).
Cause: a file with onBar() runs on the chart's own candles without an input(...) line, but it still has to declare what it draws: with no output(...) there is no row to fill.
Fix: declare at least one output, even a none, and write it in onBar() through its out_<name>() writer.
onBar must be a function with no arguments that returns nothing
Symptom: on the hook's own line: onBar must be a function with no arguments that returns nothing: write function onBar(): void { ... } (the build calls it once per bar), or the same for onStart (ending (the build calls it once, before the first bar)) and onReset (ending (the build calls it when the host resets the run)).
Cause: a hook with an argument (onBar(x: i32)), a return type other than void or none at all (function onBar() {}), a type parameter (onBar<T>()), or the name onStart / onReset bound to something that is not a function (const onReset = 1;).
Fix: write the hook exactly as the message shows: a plain top-level function with no arguments and : void. An arrow (const onBar = (): void => {}) is not seen as a hook at all; the file then counts as one without onBar(), and with no import lines its declarations are not read (This indicator declares nothing, above).
uses the prefix __wrun_lean_, which the build keeps for the functions it adds around onBar()
Symptom: on the line of its first use: '__wrun_lean_x' uses the prefix __wrun_lean_, which the build keeps for the functions it adds around onBar(); rename it.
Cause: in a file with onBar() the build adds its own functions around yours under that prefix, so a name of yours that starts the same way would collide with them.
Fix: rename it; any other spelling is free.
is already declared with another feed; rename the declared input
Symptom: on the line of the first bar.close(): bar.close() reads the chart's own ohlcv.close through an input named 'close', and input 'close' is already declared with another feed; rename the declared input (open, high, low, close, volume and bar_t are the bar's own names), or the same for open, high, low, volume and bar_t (bar.time()).
Cause: bar.close() adds an input named close on the chart's own close to the sheet (or reuses an input("close", ohlcv.close) line with no options), and the file declares an input under that name that reads something else: a pinned market, another interval, a missing policy, or another source.
Fix: rename the declared input (input("btc", ohlcv.close, { symbol: "BTCUSDT", exchange: "BINANCE_FUTURES" })) and read it with in_btc(). The same name is fine in a file that never reads that field through bar.
strategy.<call>(...) needs a top-level strategy({ ... }) declaration
Symptom: on the first order call: strategy.<call>(...) needs a top-level strategy({ ... }) declaration in src/indicator.ts (an empty strategy() enables the channel with the engine's defaults).
Cause: strategy.long("L").send() or another order call or getter in a file that never declares strategy(...), so the sheet has no strategy section for the Strategy Tester to run.
Fix: add strategy({ ... }) (or an empty strategy()) at the top level with the other declarations (Strategies overview).
celled input 'profile' needs max_cells
Symptom: celled input 'profile' needs max_cells, e.g. input("profile", volume_profile.cells, { max_cells: 512 }) (guests preallocate from it and the host refuses bigger blocks).
Cause: a celled input (volume_profile, book, intrabar, trade_volume_by_size, options_chain) preallocates its block once, so the cap is part of the declaration.
Fix: add max_cells, sized for the largest block the bar can carry. A block over the cap is refused at run, never truncated (below).
input 'btc-close' and 'btc_close' both escape to accessor 'in_btc_close'
Symptom: the declarations stage says the two names both escape to accessor 'in_btc_close'; rename one so generated accessors stay unambiguous.
Cause: an accessor name is the declared name lowercased with every run of characters outside [a-z0-9_] collapsed to _. Two names that escape to the same identifier would silently share one accessor.
Fix: rename one of the two so the escaped forms differ. Prefer snake_case names in the file and the accessors read as written.
param names 'fastLen' and 'fastlen' differ only by case
Symptom: the declarations stage says param names 'fastLen' and 'fastlen' differ only by case; the build reads names without case (both would be 'fastlen'), so rename one, on the second declaration's line. Outputs, inputs, string slots, frames, renderers, drawings, levels and panels say the same with their own word; box, segment and alert names keep their spelling, so Zone and zone are two boxes.
Cause: names may carry capitals, but the build reads them without case: params, inputs, string slots and frames are stored lowercase, and every accessor is lowercase (p_fastLen() and p_fastlen() are one reader). Two names that differ only by case would be one setting, or share one accessor.
Fix: rename one of the two.
raw positional slots rebind silently when the sheet changes
Symptom: a lint row per finding, such as Raw slot literal 0 passed to getFloat(): raw positional slots rebind silently when the sheet changes: use in_close() from ./gen/inputs in state() or p_period() from ./gen/params in init().
Cause: getFloat(0), setOutput(0, ...), and the raw host imports bind by position and rebind when a declaration is added above them.
Fix: use the accessor the message names (in a file with onBar(), read it there). The raw host calls stay available for variable-index access only.
default above max
Symptom: a metadata row on the param's line: Param 'period' (default): default above max, default below min, or min must be <= max.
Cause: the derived sheet is checked with the same schema the registry and the runtime use; a default outside its own range fails there.
Fix: move the default inside the range, or widen the range.
an output cannot color itself with color_by
Symptom: a metadata row on the output's line: Output 'price' (color_by): an output cannot color itself with color_by, color_by 'regime' does not match a declared output, or color_by needs 'colors' with at least 2 entries.
Cause: color_by names a different, declared output (usually a data-only none), and colors lists at least two entries.
Fix: declare the decision output and name it; give the palette two or more entries. width_by and widths follow the same rules (width_by needs 'widths' beside it (both or neither)), and shape_where cannot gate its own output (shape_where 'gate' does not match a declared output when the gate is missing).
has a name the sheet refuses
Symptom: Output 'my line' has a name the sheet refuses: use letters, digits, dots, dashes and underscores, starting with a letter or digit (no spaces). (or the same for a param, an input, or a string slot).
Cause: declared names become keys of the sheet and the accessors, and a space or a symbol cannot be one.
Fix: rename it within the rule: my_line, ema.fast, rsi-14.
color must be a hex, rgb() or hsl() color (the fill takes the opacity)
Symptom: boxes.0.color: color must be a hex, rgb() or hsl() color (the fill takes the opacity).
Cause: a named color ("red") cannot carry an alpha channel, and the box fill applies the opacity to its color.
Fix: use "#ef4444", "rgb(239, 68, 68)", or "hsl(0, 84%, 60%)". Segment and output colors are free-form strings; only the box fill has this rule.
a literal bar offset must be within -500..500 bars of the current bar
Symptom: segments.0.x_from: a literal bar offset must be within -500..500 bars of the current bar.
Cause: a literal offset (whole or fractional) stays within 500 bars of the current bar.
Fix: stay within the range, or pass an output handle for a longer or data-driven reach: its per-bar value is truncated to the offset, and any offset clamps to the loaded range.
boxes must declare at most 16 entries
Symptom: boxes: boxes must declare at most 16 entries or segments: segments must declare at most 16 entries.
Cause: sixteen of each per indicator.
Fix: a repeating pattern is one declaration gated per bar, not one declaration per occurrence. The zone tracker draws every zone a side ever has with one box and a when gate; for objects that live and move across bars, use a drawing handle (Drawing objects).
box name 'range' is already taken by an output
Symptom: boxes.0.name: box name 'range' is already taken by an output; box and segment names must be unique across outputs, boxes, segments, renderers, and drawings.
Cause: one namespace for everything drawn.
Fix: rename the shape.
the primary input (index 0) cannot declare missing: "carry"
Symptom: inputSources.close.missing: the primary input (index 0) cannot declare missing: "carry": its rows define the request grid, so there is no earlier bar to carry a missing one from; declare "nan" or "zero" to densify the grid instead.
Cause: the first input(...) is the grid.
Fix: give it no missing policy (the usual case), or "zero" / "nan" to densify a sparse primary; put "carry", "zero", or "nan" on the secondary inputs (Data sources).
source 'trades' requires a side (BUY or SELL)
Symptom: inputSources.buy.side: source 'trades' requires a side (BUY or SELL) or inputSources.iv.tenor: source 'implied_volatility' requires a tenor (ONE_D, THREE_D, ONE_W, ONE_M, TWO_M, THREE_M, SIX_M, ONE_Y).
Cause: the per-source knobs: side on trades, tenor on implied_volatility and skew, fund on the ETF feeds (source 'etf_holdings' requires a fund ...), publisher and series on economic, token on token_supply.
Fix: add the knob to the input's options: input("buy", trades.volume, { side: "BUY" }). For a tenor, pick one the chart serves: ONE_W, ONE_M, TWO_M, THREE_M, or SIX_M (ONE_D, THREE_D and ONE_Y are refused when the run starts, below).
feed sources pin a fixed market with symbol AND exchange together
Symptom: inputSources.btc.exchange: feed sources pin a fixed market with symbol AND exchange together (never one alone: symbols are venue-native, so a lone symbol or a lone exchange names a market that does not exist on that venue); pin both, or omit both to follow the selector.
Cause: a symbol without an exchange, or the reverse.
Fix: pin both, spelled the way the venue spells them (Exchange and symbol format), or neither to follow the chart. A Polymarket odds input is the exception: it pins the condition id in symbol alone.
max_bytes must be <= 4096 (the per-slot byte cap)
Symptom: String slot 'note' (max_bytes): max_bytes must be <= 4096 (the per-slot byte cap), renderers.0.size: size must be >= 6, renderers.0.cells: table 'stats' declares 2x2 = 4 cells but lists 3, renderers.0.text: 'note' does not name a declared string slot, or renderers.0.y: 'mid' does not name a declared numeric output.
Cause: text fields name string slots, numeric fields name outputs, and the two never substitute for each other; text sizes are 6..64 pixels; a table lists exactly rows * cols cells; a slot holds at most 4,096 bytes.
Fix: declare the slot or output the renderer names, and keep the numbers inside the caps (Drawing objects).
Conversion from type 'f64' to 'i32' requires an explicit cast.
Symptom: a compiler row with the squiggle under the value, followed by the hint Numbers convert explicitly in AssemblyScript: wrap the value in i32(), u32() or f64() (a switch needs an integer, an f64 slot needs f64). A typical line is function onStart(): void { sma = new Sma(p_period()); }, with the squiggle under p_period().
Cause: the file is AssemblyScript, TypeScript syntax over fixed-width numbers. Params and inputs are f64; a class period, a loop bound, an array index, or a counter declared as let count = 0 (an integer) is i32, and the compiler refuses to guess.
Fix: write i32(p_period()), put i32(...) around any float used as an integer, and declare float variables as f64 (let value: f64 = 0.0). Going the other way, an integer written to an output widens with f64(count):
param("period", 20, { min: 1, max: 200 });
output("bars_above", line, lower, { description: "Consecutive bars closing above the average" });
let sma = new Sma(20);
let streak: i32 = 0; // an integer counter: declare the type, never let it default from a float
let above: bool = false; // a truth value: compare to get one, never assign a number
function onStart(): void {
// Params are f64; a period is i32, so the cast is explicit.
sma = new Sma(i32(p_period()));
}
function onBar(): void {
const close = bar.close();
const average = sma.update(close);
if (isNaN(average)) return;
above = close > average;
streak = above ? streak + 1 : 0;
// Outputs are f64; an integer goes out through an explicit widening.
out_bars_above(f64(streak));
}Conversion from type 'f64' to 'bool' requires an explicit cast.
Symptom: the compiler points at an assignment of a number to a bool.
Cause: ready = value where ready is a bool and value an f64. A number is not a truth value here.
Fix: compare: ready = !isNaN(value), above = close > average. (if (value) on a number does compile, as a nonzero test; write the comparison you mean anyway.)
Module 'src/gen/outputs' has no exported member 'out_sma'.
Symptom: Cannot find name 'out_sma'. at every call site, with the hint out_sma would be generated from a output("sma", ...) declaration; declare it at the top level, or match the name you declared. In a file with the four functions, which imports its accessors, the import line fails first: Module 'src/gen/outputs' has no exported member 'out_sma'.
Cause: you renamed or removed a declaration and the generated accessor went with it, or the call misspells the name. The accessors are generated from the declarations on every check, so the compiler names every stale call (and every stale import).
Fix: update the call: output("average", ...) is out_average(...), param("fast_len", ...) is p_fast_len(), input("btc_close", ...) is in_btc_close().
Cannot find name 'close'.
Symptom: Cannot find name 'close'. (or 'hl2', 'na', 'bar_index'), usually in code carried over from Pine Script.
Cause: nothing is in scope by name except the kit, the readers and writers generated from your declarations, the bar's own fields through bar, and what you declare yourself. The hint says what the name should become: a bar series is the bar's own field (close is bar.close(), high is bar.high(); anything else is a declared input read with in_<name>()), and a Pine builtin has its own spelling (na is NaN, tested with isNaN(x); hl2 is (bar.high() + bar.low()) / 2.0; bar_index is a counter you increment in onBar()).
Fix: follow the hint. A Cannot find name on something that was never an accessor, a series, or a kit class is a plain undeclared variable.
this line uses a syntax form the build cannot read yet in a file with onBar()
Symptom: this line uses a syntax form the build cannot read yet in a file with onBar() (syntax node kind <n>); rephrase the line, or write the file with the four exported functions (init, state, finalize, reset), which take every form the compiler does, on the line in question.
Cause: a file with onBar() is read through the compiler's own syntax tree to find the names it uses, and that line holds a form the reader does not know. Every form the editor's compiler accepts today is known, so the message is not expected on any file; it is the build refusing loudly rather than guessing.
Fix: rephrase the line (a plain function, let, if, for, switch, class or arrow is always readable); if it persists, the message names the other way out.
finalize() must be declared as finalize() -> void
Symptom: in a file with the four functions (init, state, finalize, reset), after a clean compile, the validate stage refuses the module on your export function finalize line: finalize() must be declared as finalize() -> void (it is () -> f64 here). Write every output through its out_<output>() writer, then call emitRow(). A missing export reads Missing export reset(): void, followed by the line to add and what the function does. A file with onBar() never meets either: the build writes those four functions around it.
Cause: a redesigned signature (init(args: Array<f64>), a finalize that returns the value) compiles under AssemblyScript and fails the contract check afterwards. The contract is exactly init(): void, state(): i32, finalize(): void, reset(): void: no parameters, and no return value except state's (Execution model).
Fix: keep the four signatures. Values leave through out_<name>(value) and emitRow(), never as return values; params arrive through p_<name>(), never as arguments.
console.* is not available in an Indicator
Symptom: the validate stage refuses console.log(...) with console.* is not available in an Indicator (it runs in a sandbox with no console). Log through the debug output instead: declare string("debug", { max_bytes: 256 }) next to the outputs and call str_debug(text) in finalize(); the lines show in the editor console. Date, Math.random(), and performance.now() are refused the same way.
Cause: the sandbox provides no host functions beyond the indicator's own: no console, no clock, no randomness.
Fix: log through the debug slot the message names, written in onBar() (Debugging); read bar time from bar.time(); derive any variation from the bar data, so a run is reproducible bar for bar.
setOutput writes an output straight to the host
Symptom: in a file with onBar(), the declarations stage says setOutput writes an output straight to the host, and a file with onBar() hands every output to the host once, after onBar() returns, so that row would overwrite it: write the output with out_<name>(...) instead, on the import line (or the @external line of your own declaration over wrun_output_f64).
Cause: each out_<name>() keeps its value for the bar, and the row goes to the host in one step after onBar() returns. A value written by slot number, around the writers, would be replaced by that row.
Fix: write every output through its out_<name>() writer. A file that needs writes by slot number keeps the four functions.
was never written: finalize() must write every declared output before emitRow()
Symptom: after a Run of a file with the four functions, a compute row: Output 'sma' (#1) was never written: finalize() must write every declared output before emitRow()., with Fix: In finalize(), call out_sma(value) for every bar state() returned 1 on, then emitRow(). The sibling row is finalize() never called emitRow(): the outputs were written but no row reached the chart. A file with onBar() never meets either: every output starts each bar as NaN, an unwritten one draws nothing on that bar, and the row is emitted for you.
Cause: a finalize() that skips a writer on some path (an early return, an if without an else), or one that never calls emitRow().
Fix: write every declared output on every ready bar (write NaN to draw nothing), then call emitRow() last.
AssemblyScript abort
Symptom: a compute row such as AssemblyScript abort: Index out of range at ~lib/array.ts:..., or one anchored on your own line when the abort came from a throw in your code.
Cause: a trap inside the module: an array read past its length, a throw, or an explicit abort(). The run stops at that bar.
Fix: guard the index (keep a count beside a ring buffer's cursor, and scan only what has been filled), and test a condition instead of throwing. For a window of past values, a History from ./sdk/stats does that guarding: ago(n) reads NaN when fewer than n + 1 values were pushed or n is outside the window (Stats, history and lists).
The run did not finish within 20 s.
Symptom: the run stops, and the overlay's Could not load chip carries the sentence with a Retry.
Cause: a while or for loop that does not end on some bar, or per-bar work that grows with history. A run queued behind another slow one can meet the deadline too, which is why this one stays on the chip instead of a standing Console row.
Fix: bound every loop by a param with a declared max, keep per-bar work constant, and Retry.
The Indicator allocated memory after init()
Symptom: The Indicator allocated memory after init() (1048576 to 1114112 bytes): the sandbox forbids growth once the bars start., with Fix: Create arrays, strings and objects once in init() and reuse them per bar; a string built per bar (concatenation, toString()) allocates too. Past the ceiling itself the run stops with memory ... bytes exceeds limit 4194304 bytes.
Cause: a new inside onBar(), an array that grows per bar, or text built with + or toString() on every bar. The memory ceiling is a fixed 4 MiB. (The message's init() is the step before the first bar, where onStart() runs.)
Fix: allocate once, at module start or in onStart(), sized from a param's declared max; build per-bar text with the allocation-free sb_* builder (Best practices).
celled source class 'tape' is not served by the browser lane yet
Symptom: the run is refused before it computes: celled source class 'tape' is not served by the browser lane yet (input 'prints').
Cause: the chart does not serve that source class (Limitations).
Fix: read what the chart serves: side-split trades.volume for buy and sell volume per bar, trade_volume_by_size for the split by trade size, volume_profile or book for the rest of the celled data (Data sources).
the browser lane serves market pins on secondary ohlcv inputs only
Symptom: before anything is fetched: Input 'funding_btc' (funding) pins the market 'BINANCE_FUTURES/BTCUSDT': the browser lane serves market pins on secondary ohlcv inputs only (typed feeds, cells and time follow the chart's own market), or ... on the primary input (index 0): the primary input follows the chart's market; market pins are served on secondary inputs only.
Cause: a market pin on a source other than a secondary ohlcv input, or on the first input.
Fix: pin another market's candles only, on a secondary input; everything else follows the chart's market (Multi-source).
the browser lane serves interval pins coarser than the chart only
Symptom: before anything is fetched: Input 'close_1m' pins interval '1m', finer than the chart's: the browser lane serves interval pins coarser than the chart only. Its siblings: not a whole multiple of the chart's interval: a pinned leg must be a whole number of chart bars, the browser lane serves interval pins on secondary ohlcv inputs and the funding and oi feeds only, and the primary input follows the chart's interval; interval pins are served on secondary inputs only. Two view mistakes stop earlier, at the sheet check: view "confirmed" needs an interval pin, and view "forming" folds rolling buckets up to WEEK.
Cause: the chart serves a pinned interval only when it is coarser than the chart's and divides into whole chart bars, and only on those sources; a view reads a pinned leg, so it needs one.
Fix: pin a coarser interval that is a whole multiple of the chart's (a 4h pin on a 1h chart, DAY on 4h), or change the chart's interval (Multi-timeframe).
pins the template's placeholder market
Symptom: a prediction-market starter refuses: Input 'yes' (odds) pins the template's placeholder market (wrun_odds_placeholder_market): paste the market's condition id (0x…) into the input's symbol and Run again. The other odds refusals: binds its market per use ... the chart has no market picker yet; pin the market's condition id (0x…) in the input's symbol and, on a 1s chart, prediction markets are served on MINUTE and coarser charts; the sheet check refuses a slug (odds sources are keyed by the Polymarket conditionId (0x + 64 hex), not the market slug) and an exchange (exchange is implicit (POLYMARKET) for odds sources).
Cause: an odds input names its Polymarket market by condition id in symbol; the templates ship a placeholder, and the chart has no picker.
Fix: paste the market's condition id into the input's symbol, drop any exchange or binding, and Run on a one-minute chart or coarser.
max_cells is 4, so the evaluation is refused (a block is never truncated)
Symptom: the run stops: input 1 bar at ts ... has 5 cells; max_cells is 4, so the evaluation is refused (a block is never truncated).
Cause: max_cells is a contract, not a hint: the module preallocates that many tuples, and a bar whose block is larger would overflow it.
Fix: raise max_cells on the input (input("profile", volume_profile.cells, { max_cells: 8192 })) and Run again. Nothing is ever truncated on your behalf. On a volume profile the indicator can do without for a bar, missing: "empty" reads such a bar as an empty block instead of stopping the run.
"Drawings capped" on the legend row
Symptom: the run draws, but the indicator's legend row says "Drawings capped" and its card reads, for example, "2,000 of 2,350 drawings": the chart drew the newest 2,000 and left the oldest out.
Cause: a segment or box drawn on every bar of a long window, or handles that are created and never deleted.
Fix: gate the shape with when so it draws only where it means something, delete handles you no longer need, or narrow the span. The chart never refuses the run for this; the 2,000 that show are the newest.
render result exceeds 8388608 bytes expanded
Symptom: a run refuses because the expanded render selection (every selected text mark, label, table cell, shape, and drawing) passed 8 MiB: render result exceeds 8388608 bytes expanded (wrun_render_result_too_large): fewer rows, shorter strings, or fewer renderers/drawings.
Cause: a per-bar text renderer over a long history, or a large table rewritten on every bar.
Fix: write the slot only on the bars that need a mark (an unwritten slot draws nothing), or move the readout to render.label, which keeps one label. The string caps refuse the same way, never truncating: string slot 0 write of 300 bytes exceeds the slot's max_bytes 256 (raise the declaration's max_bytes, up to 4,096), over the per-row limit 65536; emit less text per bar, and over the per-run limit 2097152; emit less text or fewer rows (text and frames together, a live session counting as one run).
data is unavailable for '...', so the indicator cannot compute.
Symptom: a toast such as Volume profile data is unavailable for 'My VP' (the volume_profile source lane answered empty or was declined), so the indicator cannot compute., or Pinned market candle (BINANCE_FUTURES/BTCUSDTT) data is unavailable for ... for a pin.
Cause: the chart asked for a source it needs and got nothing back: a market the venue does not serve that source for, or a misspelled pin.
Fix: switch to a market that serves the source, or correct the pin's spelling (Exchange and symbol format).
Other messages from a run
funding field 'rate_open' is not served by the browser lane: the chart servesfunding.rate_closeonly, as a percent normalized to a one-hour interval.- A tenor the chart does not serve (
ONE_D,THREE_DorONE_Yonimplied_volatilityorskew): the run is refused naming the tenor. The chart serves five,ONE_W,ONE_M,TWO_M,THREE_MandSIX_M, from the coin's Deribit summaries. - A feed the chart in front of you cannot have:
options_oi,options_volumeandethena_positionsneed a BTC or ETH chart,long_short_ratioa chart of 5 minutes or coarser,token_supplya chart coarser than one minute and a token the chart lists,economica publisher the chart knows, a pinnedoptions_chainvenue a coin that venue lists. Each is refused before anything is fetched, with a message naming the input and the reason. Input 'flow' (etf_flow) needs a chart of a coin with listed spot ETFs (BTC, ETH, SOL)andInput 'flow' (etf_flow) pins fund 'IBIT', not one of the ETH spot ETFs (...): the class follows the chart's coin; open a BTC, ETH, or SOL chart, or declare one of that coin's funds (the message lists them) orall.input 'es' pins exchange CME: wrun_pin_venue_refused: CME is CME Group market data and cannot be read from another market's script: a CME Group venue (CME,CBOT,NYMEX,COMEX,GLOBEX) cannot be pinned; pin an ETF on the same market (SPY/USDonPOLYGON) or leave the input out.input 'spy' pins symbol "SPY/USD + CME|ES1!": wrun_pin_symbol_literal: ...: a pin names one market; give each market its own input.Input 'spx' pins SPX on POLYGON_INDICES; index series (SPX, NDX, VIX, DJI) are not served yet: ...: a warning, not a failure. The input reads its missing fill (NaN) on every bar; pin an ETF instead (SPY/USD,QQQ/USD).Input 'spy' pins interval '3d' on POLYGON/SPY/USD: a multi-day candle on a session venue groups trading days ...: a3dcandle on a stock, forex or gold market would close too early; pin1dor1w(Stocks, forex and gold).Nothing was drawnandis NaN on all ... ready bars: see Ran but blank.
Messages from the chart
- Indicator checks are unavailable: (a warning row) and Run failed before it started:: the browser could not load the compiler (an offline tab, a blocked worker). Reload; nothing in the file is wrong.
- Publish is available once the Indicator has no errors: clear the Console's errors first; Publish unlocks once the code builds cleanly.
- The publish window was blocked. Allow popups for this site and try again., OpenMarket did not answer in time. Try again., and Publish failed: followed by the registry's reason (a version that already exists, for one): the publish itself, not your file (Publishing).
- Where this Indicator runs was fixed by its first version: keep the same sharing choice.: a later version cannot switch between the browser choices (Compiled, Open source) and Protected. Publish under a new name to move it.
- The source is 300 KB; the limit is 256 KB.: Open source code is capped at 256 KB; publish the code Compiled (readers get a compiled module, never the source), or trim it.
- Run is paused on CME markets. Switch to a non-CME symbol to run this script.: drafts cannot read CME data; switch the chart to a non-CME market to Run.
- Publish first, Publish the current version first, and Runs in the browser. Only a Protected Indicator runs in the cloud.: the editor's Run on menu runs in the cloud only for a published Protected indicator whose published version matches your code.
- The console does not run strategy Indicators; Run the tab and inspect its outputs. and This Indicator reads ...; the console runs over the chart's candles only.: the Console prompt compiles expressions over the chart's candles only. Run the tab, then read outputs by name at the prompt (Debugging).
- Publish the Indicator before adding an alert.: an alert needs a published version. Publish, then add the alert on the published indicator (Alerts).
- This Indicator is pinned to a different interval than the chart. and This Indicator reads a data source alerts cannot evaluate yet.: OpenMarket's alerts engine reads another market's candles and a coarser pin that is a whole multiple of the chart's interval, over at most 600 bars, but not every pin or feed. A pin on the first input, a finer pin, a custom timeframe, a
formingview too long for those 600 bars, or a feed alerts do not read keeps its alerts off (Alerts). - This Indicator reads a market alerts cannot evaluate yet (an index). and Indicator alerts are not allowed on this venue.: an alert evaluates pinned stock, forex and gold candles, but not an index pin or a CME Group market (Alerts).
- This Indicator was built for a runtime version alerts do not support. Rebuild and publish it again.: the message is the fix.
- Indicator alerts are not enabled yet. and Only price alerts are available on CME markets right now.: alerts on wrun indicators are switched off there.
Ran but blank
An indicator that builds cleanly and draws nothing has no error to show, only a symptom. For a draft, the Console turns the commonest into a warning after a Run: Output 'sma' is NaN on all 480 ready bars, so nothing is drawn for it. (A file with the four functions can also hear Nothing was drawn: state() returned 0 on all 500 bars, so every bar counted as warm-up.)
| Symptom | What is happening | Fix |
|---|---|---|
| nothing on any bar | every output is NaN on every bar: a class whose period exceeds the loaded history, or a guard that sends onBar() back before it writes | load more history; read the guard at the Console prompt, or log it (Debugging) |
| a line is empty on every bar | the output is NaN on every bar (written so, or never written), or it is declared none | find the first NaN input; change the plot kind |
| a line stops partway | a value that went NaN mid-history: a division by zero, a missing: "nan" secondary with no more observations | guard the division; choose "zero" or "carry" |
| very few marks | a shape gate that rarely fires | usually intentional; lower the threshold to check the gate works |
| a pinned input is empty | an index pin, or no candle closed yet | pin an ETF (SPY/USD); check for NaN |
| the newest bar moves, older ones hold | the forming bar re-evaluates as live updates arrive, at most about once a second | expected: a bar's value settles when the bar closes |
The workflow that turns a symptom into the line that causes it is in Debugging.