On this page
Understand every stage that can reject or warn about a script.
Atlas validates source before it runs, reports precise line and column spans, and protects the runtime from unbounded arrays, recursion, and loops. Use this reference to translate a diagnostic code into the rule, the likely cause, and a concrete correction.
How Atlas validates a script
- Lex: split source into identifiers, keywords, literals, punctuation, and operators; report malformed characters, names, numbers, and strings.
- Parse: build declarations, statements, and expressions; report missing punctuation, malformed signatures, and incomplete constructs.
- Analyze: resolve names, scopes, types, calls, members, event restrictions, return paths, constants, arrays, structs, enums, and references.
- Compile: lower the analyzed module to VM instructions, global slots, functions, events, constants, and reference paths.
- Run: dispatch the compiled event handlers, giving each event its own instruction budget and enforcing the call-depth limit, and write runtime errors to the session log.
The native compile pipeline still produces a partial program for tests to inspect after an error, but the application checks the result and does not run a program that contains any error-severity diagnostic.
Severity levels
Error
The program is not safe or well-formed enough to run. Correct every error before Build and Run can succeed.
Warning
The program can compile, but the code is suspicious, unreachable, ambiguous, or likely not doing what was intended.
Info
Guidance that does not block compilation, such as a suggestion to add runnable event logic.
Source text and literal errors
| Code | Cause | Correction |
|---|---|---|
atlas.invalid_number | A decimal-looking token contains more than one decimal point, such as -415.54.45. | Use one point: -415.5445, or split the intended expression with an operator. |
atlas.identifier_starts_with_digit | A name starts with a digit, such as 3samples. | Start with a letter or underscore: samples3 or _3samples. |
atlas.unterminated_string | A single- or double-quoted string reaches a newline or end of file before its matching quote. | Add the matching quote and use \n for an embedded line break. |
atlas.unclosed_block_comment | A /* block comment reaches the end of the file without */. | Add the closing */; otherwise the remaining source is comment text. |
atlas.unexpected_character | The lexer found punctuation that is not part of Atlas syntax, such as a single |, #, or unsupported operator. | Use a supported operator or remove the character. |
atlas.too_deep | Source nesting or an expression/member/operator chain exceeded the parser's safety budget. | Split the expression into named intermediate values or flatten deeply nested blocks. |
var first = -415.54.45;
var second = 1.2.3.4;
var third = .5.6;
var first = -415.5445;
var second = 123.4;
var third = .56;
Scientific notation such as 1e3 is not a number form in the current lexer, and
a trailing-dot spelling such as 1. is not a complete decimal. Use
1000 and 1.0 instead.
Syntax and delimiter errors
| Code | What Atlas expected | Typical fix |
|---|---|---|
atlas.missing_semicolon | The end of a declaration or statement. | Add ; after the preceding expression, call, declaration, return, break, or continue. |
atlas.missing_brace | } closing a block, aggregate, or struct. | Balance opening and closing braces and check the nearest earlier block. |
atlas.missing_open_brace | { beginning a required function/event block. | Add a block after the signature. |
atlas.missing_bracket | ] closing an array dimension, list, or index. | Balance the nearest [. |
atlas.expected_paren | ( or ) around a condition, call arguments, or signature. | Balance the call or control-flow parentheses. |
atlas.expected_expression | A value, name, call, list, or grouped expression. | Supply the missing operand or remove the stray operator/delimiter. |
atlas.expected_member | A member name after . or enum member after ::. | Add a valid member name. |
atlas.missing_initializer_value | A value after =. | Write an initializer, such as var count = 0;, or remove =. |
atlas.do_without_while | A trailing while (condition); after a do body. | Complete the do-while statement, including its final semicolon. |
Malformed declarations
atlas.malformed_event_signature,
atlas.malformed_function_signature,
atlas.malformed_enum, atlas.malformed_struct, and
atlas.malformed_struct_field mean the construct could not be shaped into its
required grammar. Compare it to these forms:
event on_frame() { ... }
function helper(var value) { ... }
enum State { idle, active };
struct Settings { var threshold = 0.5; };
Names, declarations, and type errors
| Code | Cause | Correction |
|---|---|---|
atlas.reserved_identifier | A name reuses a language keyword, for example struct const or var target. | Choose a descriptive non-keyword name such as TargetSettings or selectedTarget. |
atlas.reserved_api_name | A variable, constant, define, parameter, for variable, function, struct, or enum uses an API name, for example Dev output; or function check(input), or an assignment to an undeclared name creates one (output = 5;): 'output' is an Atlas name; choose another name. The list is under Reserved names. | Rename it, such as output to outputValue; the editor's quick fix renames the declaration and every use of it. A struct field, an enum member, and the parameters of event on_input(input, output) may use an API name. |
atlas.undeclared_variable | A variable is read or assigned without a visible declaration. | Declare it globally or earlier in the current block. |
atlas.assign_to_event_object | An assignment replaces an event's own object, for example output = 5; in event on_input(input, output): 'output' is the event's object and cannot be assigned; use its members instead, like output.set_button(...). | Write through the object instead, such as output.set_button("cross", true);, or read from it, such as input.time. |
atlas.duplicate_declaration | The same variable/const/define name appears twice in one scope. | Remove one declaration or use a distinct name. Inner-scope shadowing is allowed. |
atlas.unknown_type | The declaration names an unknown struct or a removed type such as int, float, or double. | Declare the struct, or use var for numeric values. |
atlas.type_mismatch | A clearly known initializer, field assignment, return flow, or argument conflicts with the expected value kind. A call to your own function has the types its return statements return; a struct, vision-type, or target declaration or a struct assignment reports it when a return with a known type returns something else (see using a result where a type is required). Atlas also reports a struct or vision value stored where a var, string, or bool is declared, and a value of the wrong kind stored in a target, model, vision, or font field or parameter; a call is reported only when every one of its return paths names that same type, none of them a value Atlas cannot type (see values, data types, and defaults). | Use the matching declaration and API result type. |
atlas.null_number | A numeric var is initialized with null. | Use a numeric sentinel such as 0, or choose a nullable value type. |
atlas.top_level_statement | Executable code appears outside a function or event. | Move the statement into the appropriate event or function. |
atlas.font_init | A brace-style font initializer has no color or contains more than color, size, and font name. | Use font.create(size, color), font.default, or a valid one-to-three-value brace initializer. |
atlas.model_init | A brace-style model initializer contains no model path/source argument. | Provide at least one value, or use models.set(path) for a source model. |
atlas.constructor_syntax | A declaration passes constructor arguments after its name, such as string label("Ready");, var total(0);, or (1, 2) after a struct variable's name. Atlas Script has no constructor syntax. The declaration still declares the name, and nothing inside the parentheses is checked. | Declare a struct variable on its own (it starts with its field defaults) and assign its fields, such as p.x = 1;. Give any other value with =: string label = "Ready";. |
struct const { var value; };
float threshold = 0.5;
event on_frame() { missing = 1; }
struct ThresholdSettings {
var value = 0.5;
};
var threshold = 0.5;
var currentValue = 0;
event on_frame() {
currentValue = 1;
}
Constant errors
| Code | Meaning | Fix |
|---|---|---|
atlas.const_needs_value | A const declaration has no initializer. | Assign a literal or deterministic expression. |
atlas.const_null | A const is initialized with null. | Use a concrete immutable value. |
atlas.const_not_compile_time | A const calls a function or tries to create a runtime-only font/model/vision tool value. | Use literals, enum members, arithmetic, strings, or array literals; make runtime resources mutable declarations. |
atlas.assign_to_const | An assignment, update, alias, member write, or element write reaches readonly storage. | Remove the mutation or use a mutable declaration. |
enum Mode {
idle,
active = 4
};
const LIMIT = 10;
const DOUBLE_LIMIT = LIMIT + LIMIT;
const LABELS[] = { "idle", "active" };
define DEFAULT_MODE = Mode::idle;
For portability, keep const and define expressions to literals, already-defined constants, enum members, arithmetic on those values, and nested lists. The native purity pass rejects calls but does not currently prove every identifier/property expression is compile-time.
Array and index errors
| Code | Cause | Correction |
|---|---|---|
atlas.array_size | A mutable array omits a size, or a dimension is zero, negative, fractional, nonliteral, or starts with zero. | Use positive fixed sizes, or infer only a const array's omitted size from its initializer. |
atlas.array_too_large | The dimensions multiply to more than 1,000,000 elements. | Reduce dimensions or process data in smaller fixed buffers. |
atlas.array_init_count | An aggregate does not exactly fill a known dimension. | Add/remove values or correct the declared size at every nesting level. |
atlas.empty_array_initializer | A declared array uses an empty aggregate. | Supply every fixed element, or omit the initializer on a mutable fixed array to receive defaults. |
atlas.brace_init_requires_array | A scalar declaration uses { ... } without being an array, font, or model constructor. | Add array dimensions, use a plain scalar, or use an appropriate typed constructor. |
atlas.array_needs_subscript | An array or partially indexed multidimensional array is used where one scalar is required. | Add the remaining [index] operations. |
atlas.index_non_array | A known scalar string/bool/font/model/target/tool or scalar struct field is indexed. | Index an array value instead. |
atlas.non_integer_index | A literal array index is fractional. | Use a whole-number index. |
atlas.negative_array_index | A constant index is below zero. | Use 0 or greater. |
atlas.array_index_out_of_bounds | A constant index is at least the known array length. | Use an index from 0 through count() - 1. |
atlas.count_non_array | .count() is called on a value the analyzer cannot prove is an array. | Call it on a declared array or struct array field. |
var samples[4] = { 2, 4, 6, 8 };
event on_frame() {
for (var index = 0; index < samples.count(); index++) {
system.log(samples[index]);
}
}
Enum and struct errors
| Code | Cause | Correction |
|---|---|---|
atlas.trailing_enum_comma | A comma appears directly before the enum's closing brace. | Remove it or add another member. |
atlas.enum_duplicate_member | The same enum member name appears twice. | Give each member a unique name. |
atlas.enum_not_constant | An enum initializer uses a call, variable, or another nonconstant expression. | Use a whole-number literal, prior member, qualified enum member, or arithmetic on them. |
atlas.enum_as_value | A bare enum name is used as a value. | Use EnumName::member. |
atlas.unknown_enum | The name before :: is not a collected enum. | Correct the enum name or add its declaration. |
atlas.unknown_enum_member | The enum has no member with that name. | Use a declared member. |
atlas.duplicate_struct | The same struct type name is declared twice. | Keep one declaration per struct type. |
atlas.duplicate_struct_field | One struct declares the same field twice. | Rename or remove the duplicate field. |
atlas.recursive_struct | A struct contains itself directly or through other struct fields. | Break the recursive layout and store a nonrecursive identifier/state value instead. |
atlas.struct_field_initializer | A field default uses runtime state or a call. | Use literals, enum members, arithmetic, or array literals. |
atlas.struct_scope | A struct is declared inside a function/event/block. | Move the struct type to top level. |
atlas.struct_as_value | A struct type name is read like an instance. | Declare an instance, then read its fields. |
Reference and assignment errors
| Code | Cause | Correction |
|---|---|---|
atlas.reference_requires_var | An alias is declared with const, string, bool, a struct type, or another non-var spelling. | Use var alias = ⌖. |
atlas.reference_cannot_be_array | An alias declaration also declares array dimensions. | Remove dimensions; the alias is one binding. |
atlas.reference_requires_variable | & targets a literal, expression, call result, namespace property, or other non-writable value. | Bind a declared writable variable, struct field, or array element. |
atlas.reference_self | An alias tries to bind itself in its own initializer. | Bind another already-declared target. |
atlas.reference_initializer_only | & appears outside the direct initializer of a var alias. | Create the alias at declaration time. Do not put & at a function call site. |
atlas.invalid_reference_parameter | A function uses & on a scalar, untyped, or unknown parameter type. | Only a declared struct type may use a shared parameter, such as Settings &settings. |
atlas.assign_to_non_assignable | The left side is a literal, call result, function, expression, or other temporary. | Assign a variable, member, or array element. |
atlas.self_assignment | A plain assignment reads and writes the same name, such as value = value;. | Remove the no-op or correct the right-hand expression. |
See Struct parameters and true aliases for the important difference between a shared struct object and a caller-slot/member/index reference path.
Function, return, and flow errors
| Code | Cause | Correction |
|---|---|---|
atlas.typed_function_header | A function header starts with a type or another name instead of function. Atlas Script functions have no return type. | Declare it as function name(parameters) { ... }; the editor's quick fix replaces the leading type with function. The function returns whatever its return statements return. |
atlas.argument_count | A user or built-in call receives too few or too many arguments. | Match the documented signature exactly. |
atlas.duplicate_parameter | One function declares the same parameter name more than once. | Give every parameter a unique name. |
atlas.argument_type | A clearly known literal/value is incompatible with a parameter, controller name, trigger, stick, color, font, or typed user parameter. | Use the parameter kind shown in the API/function declaration. |
atlas.void_result | A no-result call is used where a value is required. | Call it as a statement, or use a method/function that returns a value. |
atlas.unused_result | A value-returning call is used as a bare statement when its result should be consumed. | Assign or use the result. An unused font.create result is an error; many others are warnings. |
atlas.missing_return | A function returns a value on one path but another structural path can reach the end. | Add a compatible return to every path. |
atlas.mixed_returns | A value-returning function mixes bare returns or incompatible value kinds. | Return one compatible kind on every path. |
atlas.event_returns_value | An event uses return expression;. | Use bare return; to exit early; store state in a variable if another event needs it. |
atlas.loop_control_outside_loop | break appears outside every loop and switch, or continue appears outside every loop. | Use break inside the intended while/do/for/switch body. Use continue only for a while/do/for loop; a switch is not a continue target. |
atlas.for_iterator_type | A for-loop iterator declaration uses a type other than var. | Use for (var index = 0; ...). |
atlas.bool_in_arithmetic | A bool participates in ordinary arithmetic. | Use a numeric value, or use the bool as a condition. |
Switch and conditional-expression errors
| Code | Cause | Correction |
|---|---|---|
atlas.expected_colon | A case/default label or ?: expression is missing its separating colon. | Add : after the case value or default keyword, or between the conditional expression's true and false arms. |
atlas.switch_expected_case | A statement appears directly in a switch where Atlas expects a case or default label. | Put the statement after a label, or move it outside the switch. |
atlas.case_outside_switch | case or default is used outside the direct body of a switch. | Move the label directly inside switch (...) { ... }. |
atlas.duplicate_default | One switch contains more than one default label. | Keep at most one default body. |
atlas.case_not_constant | A case label depends on runtime state or another value that cannot be folded at compile time. | Use a scalar literal, enum member, define, const value, or compile-time constant expression. |
atlas.duplicate_case | Two labels in the same switch fold to the same case value. | Remove or change one of the duplicate labels. |
atlas.switch_case_type | A case value kind is incompatible with the switch value kind. | Use the same kind as the switch value. Number and bool are mutually compatible. |
atlas.conditional_missing_true | The editor finds no result expression between ? and :. | Add the value to use when the condition is truthy. |
atlas.conditional_missing_false | The editor finds no result expression after the conditional :. | Add the value to use when the condition is falsey. |
atlas.conditional_type_mismatch | The two ?: result arms have incompatible kinds or use different named struct types. | Return compatible values from both arms. Number and bool may mix, and null may pair with another result kind. |
Event, member, and controller-context errors
| Code | Cause | Correction |
|---|---|---|
atlas.event_parameters | An event other than on_input declares parameters. | Use an empty parameter list. |
atlas.controller_outside_on_input | A physical controller read/write/feedback/motion/platform root appears outside the lexical body of on_input. | Move it directly into on_input. Pass already-read scalars to pure helpers. |
atlas.packet_outside_network_event | The packet object appears outside on_network_recv or on_network_send, where there is no current packet. | Use packet only inside the two network events. network.* is allowed in any event, although network.capture() returns false in global initializers and on_stop. |
atlas.qualify_button | A bare name such as L2 or cross is treated as an undeclared variable rather than a controller constant. | Use a quoted name or a platform-view name such as ps5.l2. |
atlas.input_control_requires_get | A named controller control such as input.l2, input.x, or input.west is read as though it were a direct property. | Pass the control name to input.get(...), such as input.get(ps5.l2) or input.get(xb.x). |
atlas.unknown_member | A known namespace, struct, font, model, target, or vision value has no such member. | Check spelling and the current API/type member table. |
atlas.renamed_api | The script uses a removed name: the xb1 or xbox root, or controller.xb1, controller.xinput, host.xb1, or cronuszen.xb1. The message names the replacement, for example xb1 was renamed to xb; use xb.rt. or controller.xb1 was renamed to controller.xb. | Use the replacement: xb, controller.xb, host.xb, or cronuszen.xb. A variable the script declares with an old spelling is not affected where it is in scope; in another function or after its block ends, the name is the removed root again. A current API root cannot be declared at all (atlas.reserved_api_name). A legacy ctx. prefix does not hide a removed name: ctx.controller.xinput and ctx.xb1.rt are reported the same way. |
atlas.renamed_value | Warning. A controller, host, or Cronus protocol value is compared with the string of a removed name: input.controller or system.controller with "xinput" or "xb1", or output.host or cronuszen.protocol with "xb1". Those values report "xb" now, so == is never true and != is always true. The script still compiles. | Compare with the constant the message names, such as controller.xb. Constants are checked when the script compiles; string literals are not. |
atlas.not_callable | A namespace member that is not a method is called, such as xb.rt(1) or input.controller(). Method names are case-sensitive, so xb.RUMBLE(10) is reported the same way. | Remove the call, or use the method's exact name, such as xb.rumble(10). |
atlas.unsupported_feedback | A console namespace is asked for feedback its controller does not have: a light bar, player LEDs or player number, or adaptive triggers on xb, or player LEDs, player number, or adaptive triggers on ps4. The message names what is missing, for example Xbox controllers have no light bar, so xb.set_lightbar is not available; xb feedback is rumble only. | Remove the call, or use a feedback family the controller has (see Feedback by controller). |
atlas.readonly_member | Code assigns or aliases a result-only vision member such as results, count, or target. | Read the member; change a documented configuration member instead. |
atlas.unknown_function | A bare call name has no declared user function or registered built-in method. | Correct the name or add the function. Native analysis currently reports this as a warning and the VM returns null. |
Controller family constants are terminal values
controller.ps5, controller.ps4, and similar values identify a
controller family for comparison. They do not contain buttons. A platform view supplies a
button/trigger name, while input.get(...) reads its live numeric state.
input.held(L2)
input.held(controller.ps5.r2)
output.set_trigger(controller.ps4.l2, 100)
event on_input() {
if (input.controller == controller.ps5 && input.held(ps5.l2)) {
var pressure = input.trigger(ps5.r2);
output.set_trigger(ps5.r2, pressure);
}
}
ps5.r2 is the string name "r2", not live trigger pressure. Read
pressure with input.get(ps5.r2) or the specialized
input.trigger(ps5.r2) reader inside on_input. Named controls are
not direct properties of input.
Warnings worth fixing
| Code | What it identifies | Why it matters |
|---|---|---|
atlas.duplicate_event | The same event appears more than once. | The native compiler records the last handler, so earlier logic will not run. Keep one block per event. |
atlas.empty_switch | A switch has an empty body with no case or default label. | Add one or more labels and their statements, or remove the switch. The selector still evaluates, but no branch can run. |
atlas.unknown_function | A call target is not known. | The VM substitutes null, usually hiding a spelling or removed-API mistake. |
atlas.unused_result | A returned value is discarded. | The call may exist only to produce a value and therefore have no useful effect. |
atlas.count_non_array | count() is used on a value not proven to be an array. | The VM returns 0 for a non-array receiver. |
atlas.self_assignment | name = name; | The statement has no effect and often indicates the wrong source name. |
atlas.constant_condition | A bare true or false condition. | The branch/loop is statically fixed and may be accidental. |
atlas.unreachable | A statement follows an unconditional return, break, or continue in the same block. | The first following statement cannot execute. |
atlas.format_placeholder_count | A literal string.format has a different number of {} placeholders and values. | Missing values become empty; extra values are ignored. |
Editor-specific diagnostic codes
The native validator uses the canonical codes in the tables above. The Monaco language service also emits narrower codes so it can underline the most useful span and suggest a precise edit before Build and Run. The exact editor spellings are listed here so every code shown in the Problems panel is searchable.
atlas.qualify_button:ps5.l2 identifies both the rule and the proposed qualified
name. Search by the stable prefix before the colon when the suffix differs.
Source structure and delimiters
| Editor code | Severity | Meaning and correction |
|---|---|---|
atlas.unclosed_block_comment | Error | A /* comment has no closing */. Close the comment; native and editor validation use the same code. |
atlas.unterminated_string | Error | A quoted string reaches a line end or file end before its matching quote. Add the closing quote; native and editor validation use the same code. |
atlas.unclosed_paren, atlas.unclosed_bracket, atlas.unclosed_brace | Error | An opening (, [, or { has no matching closer. |
atlas.unexpected_close_paren, atlas.unexpected_close_bracket, atlas.unexpected_close_brace | Error | A closer appears without its matching opener, or closes delimiters in the wrong order. |
atlas.missing_expression, atlas.missing_operator, atlas.missing_comma | Error | An expression or argument list is missing an operand, operator, or comma at the highlighted location. |
atlas.unexpected_operator, atlas.unexpected_token | Error | An operator/value appears where the current expression cannot accept it. Check the neighboring operands and separators. |
atlas.add_open_brace | Warning | An event or control-flow header has no visible opening block brace. Add {. |
atlas.unexpected_semicolon | Error | A semicolon separates an event/control-flow header from its block. Remove the semicolon before {. |
atlas.missing_declaration_name | Error | A declaration type is followed by =, ;, [, or ( instead of a name. |
atlas.unexpected_parameter | Error | A parameter is missing its name or contains unsupported punctuation/trailing tokens. Use one optional type plus one name. |
atlas.use_event_syntax, atlas.unsupported_gpc | Error | The source resembles Python/GPC def, main, combo, wait, get_val, or set_val. Rewrite it with Atlas events and APIs. |
atlas.unsupported_for_in | Error | A for (item in values) loop uses unsupported for-in syntax. Use an indexed loop such as for (var i = 0; i < values.count(); i++). |
Events, calls, and members
| Editor code | Severity | Meaning and correction |
|---|---|---|
atlas.unknown_event | Error | The callback name is not one of on_start, on_connect, on_frame, on_input, or on_stop. |
atlas.invalid_event_parameters | Error | An event other than on_input declares parameters. Native validation uses atlas.event_parameters. |
atlas.missing_callback | Info | No runnable on_connect, on_frame, or on_input block exists. Add the event that should perform work. |
atlas.event_object_unavailable | Error | Code expects an event.* packet object. Read controller state from input and write through output. |
atlas.missing_argument, atlas.too_many_arguments | Error | A built-in call does not match its minimum/maximum argument count. Native validation groups these under atlas.argument_count. |
atlas.argument_range | Warning | A known numeric literal is outside the documented pressure, axis, color, coordinate, byte, player, or unit range. |
atlas.not_callable | Error | A known property/member is followed by (...) even though it is not a method. Native validation reports the same code. |
atlas.readonly_api | Error | Code assigns a read-only built-in property. Native validation may report atlas.readonly_member. |
Names, constants, and configuration guidance
| Editor code | Severity | Meaning and correction |
|---|---|---|
atlas.unknown_button, atlas.unknown_trigger, atlas.unknown_stick, atlas.unknown_rumble_motor | Error | A controller name is not recognized for that argument. Use the API reference's canonical names. |
atlas.unknown_color | Warning | An overlay color string is not #RRGGBB or 0xRRGGBB, the only forms the runtime reads; the overlay keeps its default color. Use one of those or an rgb.* constant. |
atlas.invalid_rgb_color | Error | A single lightbar color is not a #RRGGBB/0xRRGGBB string, so the runtime leaves the lightbar unchanged. Use such a string, an rgb.* constant, or three byte values (r, g, b). |
atlas.unknown_adt_field | Error | An adaptive-trigger field/byte name is invalid. Use a documented ps5.adt.* field. |
atlas.qualify_button:<qualified-name>, atlas.qualify_adt_constant:ps5.adt.<field> | Error | A bare controller/ADT name needs the qualified spelling provided after the colon. |
atlas.quote_literal:<name> | Error | A name-like string argument lacks quotes. Use the quoted suggestion carried after the colon. |
atlas.backend_constant:vision.<backend> | Error | A vision backend was written as a string. Use the suggested vision.* constant. |
atlas.replace_button:<preferred-name> | Info | A compatibility button name works, but the suffix supplies the simpler canonical Atlas name. |
atlas.renamed_api:<new-name> | Error | The editor spelling of the native atlas.renamed_api. The marked name (such as xb1) was removed; the quick fix replaces it with the name after the colon (such as xb). |
atlas.unknown_ctx_branch | Error | A legacy ctx.* root has no matching API branch. Prefer the canonical root directly. A removed root behind the prefix, such as ctx.xb1, is reported as atlas.renamed_api:xb instead. ctx is a reserved name, so a script cannot declare its own. |
atlas.unknown_model | Warning | A literal models.path(name) has no matching two-argument models.set(name, path) registration. |
atlas.model_profile | Info | A legacy hint suggests moving a literal ONNX path into a script profile. The current Recipes-only tools panel has no profile editor, so use a generic project-relative path with models.set. |
atlas.unused_variable | Info | A non-underscore variable is assigned but not read later. Remove it, use it, or prefix an intentionally unused value with _. |
Unsupported or removed constructs
Some familiar-looking spellings are intentionally absent or were removed from the current runtime. They should not appear in new scripts or recipes.
| Do not use | Reason or replacement |
|---|---|
A type before a function name, such as string label(bool active) { ... } | Functions have no return type. Declare every function with function: function label(bool active) { ... }. Otherwise the header is the error atlas.typed_function_header. |
Constructor arguments on a declaration, such as string label("Ready"); or (1, 2) after a struct variable's name | Atlas Script has no constructor syntax (atlas.constructor_syntax). A struct variable starts with its field defaults; assign its fields afterwards. Give any other value with =. |
int, float, double declarations | Use var for whole and decimal numbers. type() may still report int32/float runtime categories. |
handle name declarations | handle is a runtime result kind, not a declaration keyword. Consume or store a returned handle in a supported value flow. |
sequence, yield, sleep, await | No sequence/coroutine scheduler exists. Keep state across event calls with globals and input.time/time_ms. |
overlay.* | Overlay behavior was merged into ui.*. |
ui.create | Removed. Use current primitives such as ui.print, ui.rect, ui.line, ui.circle, and ui.status. |
ui.format | Use string.format. |
| Plural vision helper names | Use the current singular typed helper, such as vision.color, vision.circle, or vision.target. |
controller.ps5.r2 | controller.ps5 is a terminal family constant. Use ps5.r2 as a name and input.get(ps5.r2) for pressure. |
| Controller APIs inside helper functions | Validation is lexical. Read/apply directly in on_input and pass scalar values to helpers. |
& at a shared-struct call site | Declare Settings &settings, then call edit(settings). |
| Scientific notation and trailing-dot decimals | Use ordinary decimal literals such as 1000 and 1.0. |
| Foreach/for-in, bitwise, classes, lambdas, imports, exceptions | These constructs are not part of the language. Use indexed loops, supported operators, functions, structs, arrays, and events. |
Runtime protections and fallback behavior
Analysis handles most deterministic errors. Runtime guards cover behavior that depends on live data or execution paths.
| Condition | Current result | How to prevent it |
|---|---|---|
| More than 40 active user calls | Script recursion is too deep (possible infinite recursion). | Add a reachable base case or replace recursion with a bounded loop. |
| More than 2,000,000 instructions in one event, or in the global initializers | Script exceeded its per-event instruction budget (possible infinite loop). That event stops; the next event starts with a full budget. | Bound loops, reduce event work, and ensure counters/conditions change. |
| Copying a struct nested more than 128 levels deep, or one that contains itself | Struct value is nested too deeply or refers to itself. That event stops; the next event runs normally. | Do not store a struct in a field of itself; copy the fields you need instead. |
| Dynamic array index outside range | Read returns null; write does nothing. | Validate index >= 0 && index < array.count(). |
| Division or remainder by zero | Produces numeric 0. | Check the divisor first rather than treating 0 as a meaningful quotient. |
| Unknown user call that remained only a warning | Produces null. | Treat unknown-function warnings as errors in practice. |
count() on a non-array | Produces 0. | Use a declared array or a known array-valued field/result. |
Runtime error, or no decision within 50 ms, in on_network_recv/on_network_send | The original packet continues unchanged and network.failed_open counts it. | Keep network events short and bounded; see Network events. |
network.capture() in a global initializer or on_stop | Returns false; network.error reads Network capture can only start while the script is running. | Start capture from on_start or a later event; see where capture can start. |
packet.* read past the end of the packet | Returns null (an empty array or string for bytes and hex); a write does nothing. | Check packet.payload_length or packet.length first. |
Atlas writes each runtime error to the session log (the Logs panel),
among your system.log lines, with the event it happened in:
Script: Runtime error in on_frame: Script exceeded its per-event instruction budget (possible infinite loop).
The first occurrence is logged at once. When the same error keeps happening in the same
event, Atlas adds at most one line every 5 seconds, ending in
(repeated N times), and a last one when the script stops.
The event stops where the error happened. Work it finished before then still counts: lines
it logged, overlays it drew, and, in on_input, the output fields it had already
set for that packet. A network event's packet continues unchanged instead.
Current implementation notes
The following details describe the current native implementation where its behavior is narrower, looser, or different from what familiar syntax may suggest. Write code that does not depend on these edge cases; they may become stricter as Atlas evolves.
- Unknown event names differ between validators. Monaco reports an unknown event, while native analysis currently allows the declaration and the runtime simply never dispatches it. Use only the seven documented names.
- Duplicate event severity differs. Native analysis warns and the last handler wins; Monaco may report an error. Keep exactly one handler per event.
on_input(input, output)names are decorative compatibility syntax. The compiler does not create event-parameter locals; the names work becauseinput/outputare built-in roots.- Shared struct parameters share the object, not the caller slot. Field writes affect the caller; replacing the whole parameter changes only the callee binding.
- Only explicitly typed struct parameters deep-copy. Passing a struct through an untyped parameter does not request the recursive copy.
- Other heap-backed values retain shared payloads. Arrays, fonts, models, targets, vision tools, and handles are not recursively copied by ordinary parameter passing.
- Scalar type enforcement is incomplete. Several declarations are checked, but later plain assignments are not uniformly validated. Keep values type-correct by design.
- An uninitialized bool is null. It is falsey, but
type(value)reports null until a bool is assigned. Initialize bools explicitly. - Const purity is conservative but not a full constant proof. Calls are rejected, yet every identifier/property dependency is not folded and proven.
- Logical expression runtime values are operand-preserving.
&&/||short-circuit but can leave an operand value while analysis calls the result bool. Use them as conditions. - Prefix/postfix updates share updated-value behavior. Do not depend on C-style old-value postfix semantics.
- Member
++/--lowering is incomplete. Use compound assignment on a member instead. - Array and struct equality is not a documented portable comparison. The current scalar fallback does not compare aggregate contents. Compare selected fields or elements explicitly.
- Duplicate function and enum type names lack complete native diagnostics. Declare each once.
- Hex validation is incomplete for a bare
0x. Always include at least one hexadecimal digit. - A dynamic fractional index is rounded by the VM. The analyzer rejects a fractional literal but cannot prove every dynamic value. Keep indices whole.
- Whole-array replacement does not uniformly preserve a declared fixed length. Prefer element writes for ordinary fixed arrays.
A corrected, validation-friendly script
This example follows the central rules: explicit types/defaults, top-level struct state,
pure helper logic, video-side state updates, and passthrough-safe controller reads/writes
directly inside on_input.
struct ScriptSettings {
var triggerThreshold = 50;
bool enabled = true;
};
function meetsThreshold(var value, var threshold) {
return value >= threshold;
}
ScriptSettings settings;
bool frameReady = false;
event on_frame() {
frameReady = settings.enabled;
}
event on_input() {
var pressure = input.get(ps5.r2);
bool active = frameReady && meetsThreshold(pressure, settings.triggerThreshold);
if (active) {
output.set_button(ps5.cross, true);
}
}
Troubleshooting workflow
- Start at the earliest error: correct missing quotes, parentheses, brackets, braces, or semicolons before reading later messages.
- Check the declaration: confirm every name exists, is in scope, is not a keyword, and uses a current type spelling.
- Check the event: move physical controller APIs directly into
on_inputand video/UI work into the appropriate frame path. - Check the value shape: fully subscript arrays, verify struct fields, use enum
::, and match typed vision values to their creator. - Check the call: match argument count, supply compatible values, consume results, and return one compatible kind on every path.
- Check sharing intent: explicitly type struct parameters and distinguish
Struct ¶meterfromvar alias = &target. - Resolve warnings: unknown calls, duplicate events, unused results, and non-array
count()often indicate real no-op behavior. - Bound runtime work: make every loop progress and every recursive function reach a base case.
Related references
Language
Review exact declaration, expression, array, enum, struct, control-flow, scope, and limit rules.
Functions & References
See correct return, copy, shared-struct, and writable-alias patterns.
Events
Match work to the lifecycle callback and legal API context.
API Reference
Confirm current methods, signatures, result kinds, members, constants, and controller names.