Browse docsScript diagnostics
On this page
Validation and troubleshooting

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

  1. Lex: split source into identifiers, keywords, literals, punctuation, and operators; report malformed characters, names, numbers, and strings.
  2. Parse: build declarations, statements, and expressions; report missing punctuation, malformed signatures, and incomplete constructs.
  3. Analyze: resolve names, scopes, types, calls, members, event restrictions, return paths, constants, arrays, structs, enums, and references.
  4. Compile: lower the analyzed module to VM instructions, global slots, functions, events, constants, and reference paths.
  5. 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.

Fix the first real error first. One missing delimiter can make later tokens appear to be in the wrong construct. Atlas includes recovery logic, but correcting the earliest source error often removes several downstream messages at once.

Source text and literal errors

CodeCauseCorrection
atlas.invalid_numberA 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_digitA name starts with a digit, such as 3samples.Start with a letter or underscore: samples3 or _3samples.
atlas.unterminated_stringA 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_commentA /* block comment reaches the end of the file without */.Add the closing */; otherwise the remaining source is comment text.
atlas.unexpected_characterThe 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_deepSource 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.
Invalid decimal examples
var first = -415.54.45;
var second = 1.2.3.4;
var third = .5.6;
Correct decimal forms
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

CodeWhat Atlas expectedTypical fix
atlas.missing_semicolonThe 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_expressionA value, name, call, list, or grouped expression.Supply the missing operand or remove the stray operator/delimiter.
atlas.expected_memberA member name after . or enum member after ::.Add a valid member name.
atlas.missing_initializer_valueA value after =.Write an initializer, such as var count = 0;, or remove =.
atlas.do_without_whileA 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:

Declaration grammar fragments
event on_frame() { ... }
function helper(var value) { ... }
enum State { idle, active };
struct Settings { var threshold = 0.5; };

Names, declarations, and type errors

CodeCauseCorrection
atlas.reserved_identifierA 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_nameA 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_variableA variable is read or assigned without a visible declaration.Declare it globally or earlier in the current block.
atlas.assign_to_event_objectAn 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_declarationThe 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_typeThe 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_mismatchA 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_numberA numeric var is initialized with null.Use a numeric sentinel such as 0, or choose a nullable value type.
atlas.top_level_statementExecutable code appears outside a function or event.Move the statement into the appropriate event or function.
atlas.font_initA 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_initA 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_syntaxA 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";.
Invalid declarations
struct const { var value; };
float threshold = 0.5;
event on_frame() { missing = 1; }
Correct declarations
struct ThresholdSettings {
    var value = 0.5;
};

var threshold = 0.5;
var currentValue = 0;

event on_frame() {
    currentValue = 1;
}
Declarations guide validation; they do not form a complete static type system. The current analyzer catches many clear mismatches but does not uniformly type-check every later scalar assignment. Keep assignments consistent with the declaration even if a particular mismatch is not yet diagnosed.

Constant errors

CodeMeaningFix
atlas.const_needs_valueA const declaration has no initializer.Assign a literal or deterministic expression.
atlas.const_nullA const is initialized with null.Use a concrete immutable value.
atlas.const_not_compile_timeA 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_constAn assignment, update, alias, member write, or element write reaches readonly storage.Remove the mutation or use a mutable declaration.
Portable constant values
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

CodeCauseCorrection
atlas.array_sizeA 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_largeThe dimensions multiply to more than 1,000,000 elements.Reduce dimensions or process data in smaller fixed buffers.
atlas.array_init_countAn aggregate does not exactly fill a known dimension.Add/remove values or correct the declared size at every nesting level.
atlas.empty_array_initializerA 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_arrayA 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_subscriptAn array or partially indexed multidimensional array is used where one scalar is required.Add the remaining [index] operations.
atlas.index_non_arrayA known scalar string/bool/font/model/target/tool or scalar struct field is indexed.Index an array value instead.
atlas.non_integer_indexA literal array index is fractional.Use a whole-number index.
atlas.negative_array_indexA constant index is below zero.Use 0 or greater.
atlas.array_index_out_of_boundsA 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.
Safe array traversal
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

CodeCauseCorrection
atlas.trailing_enum_commaA comma appears directly before the enum's closing brace.Remove it or add another member.
atlas.enum_duplicate_memberThe same enum member name appears twice.Give each member a unique name.
atlas.enum_not_constantAn 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_valueA bare enum name is used as a value.Use EnumName::member.
atlas.unknown_enumThe name before :: is not a collected enum.Correct the enum name or add its declaration.
atlas.unknown_enum_memberThe enum has no member with that name.Use a declared member.
atlas.duplicate_structThe same struct type name is declared twice.Keep one declaration per struct type.
atlas.duplicate_struct_fieldOne struct declares the same field twice.Rename or remove the duplicate field.
atlas.recursive_structA struct contains itself directly or through other struct fields.Break the recursive layout and store a nonrecursive identifier/state value instead.
atlas.struct_field_initializerA field default uses runtime state or a call.Use literals, enum members, arithmetic, or array literals.
atlas.struct_scopeA struct is declared inside a function/event/block.Move the struct type to top level.
atlas.struct_as_valueA struct type name is read like an instance.Declare an instance, then read its fields.

Reference and assignment errors

CodeCauseCorrection
atlas.reference_requires_varAn alias is declared with const, string, bool, a struct type, or another non-var spelling.Use var alias = &target;.
atlas.reference_cannot_be_arrayAn 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_selfAn 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_parameterA 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_assignableThe left side is a literal, call result, function, expression, or other temporary.Assign a variable, member, or array element.
atlas.self_assignmentA 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

CodeCauseCorrection
atlas.typed_function_headerA 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_countA user or built-in call receives too few or too many arguments.Match the documented signature exactly.
atlas.duplicate_parameterOne function declares the same parameter name more than once.Give every parameter a unique name.
atlas.argument_typeA 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_resultA 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_resultA 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_returnA function returns a value on one path but another structural path can reach the end.Add a compatible return to every path.
atlas.mixed_returnsA value-returning function mixes bare returns or incompatible value kinds.Return one compatible kind on every path.
atlas.event_returns_valueAn event uses return expression;.Use bare return; to exit early; store state in a variable if another event needs it.
atlas.loop_control_outside_loopbreak 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_typeA for-loop iterator declaration uses a type other than var.Use for (var index = 0; ...).
atlas.bool_in_arithmeticA bool participates in ordinary arithmetic.Use a numeric value, or use the bool as a condition.

Switch and conditional-expression errors

CodeCauseCorrection
atlas.expected_colonA 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_caseA 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_switchcase or default is used outside the direct body of a switch.Move the label directly inside switch (...) { ... }.
atlas.duplicate_defaultOne switch contains more than one default label.Keep at most one default body.
atlas.case_not_constantA 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_caseTwo labels in the same switch fold to the same case value.Remove or change one of the duplicate labels.
atlas.switch_case_typeA 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_trueThe editor finds no result expression between ? and :.Add the value to use when the condition is truthy.
atlas.conditional_missing_falseThe editor finds no result expression after the conditional :.Add the value to use when the condition is falsey.
atlas.conditional_type_mismatchThe 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

CodeCauseCorrection
atlas.event_parametersAn event other than on_input declares parameters.Use an empty parameter list.
atlas.controller_outside_on_inputA 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_eventThe 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_buttonA 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_getA 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_memberA known namespace, struct, font, model, target, or vision value has no such member.Check spelling and the current API/type member table.
atlas.renamed_apiThe 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_valueWarning. 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_callableA 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_feedbackA 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_memberCode 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_functionA 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.

Invalid controller paths
input.held(L2)
input.held(controller.ps5.r2)
output.set_trigger(controller.ps4.l2, 100)
Correct controller context and names
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

CodeWhat it identifiesWhy it matters
atlas.duplicate_eventThe 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_switchA 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_functionA call target is not known.The VM substitutes null, usually hiding a spelling or removed-API mistake.
atlas.unused_resultA returned value is discarded.The call may exist only to produce a value and therefore have no useful effect.
atlas.count_non_arraycount() is used on a value not proven to be an array.The VM returns 0 for a non-array receiver.
atlas.self_assignmentname = name;The statement has no effect and often indicates the wrong source name.
atlas.constant_conditionA bare true or false condition.The branch/loop is statically fixed and may be accidental.
atlas.unreachableA statement follows an unconditional return, break, or continue in the same block.The first following statement cannot execute.
atlas.format_placeholder_countA 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.

Codes with a colon carry their suggested replacement. For example, 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 codeSeverityMeaning and correction
atlas.unclosed_block_commentErrorA /* comment has no closing */. Close the comment; native and editor validation use the same code.
atlas.unterminated_stringErrorA 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_braceErrorAn opening (, [, or { has no matching closer.
atlas.unexpected_close_paren, atlas.unexpected_close_bracket, atlas.unexpected_close_braceErrorA closer appears without its matching opener, or closes delimiters in the wrong order.
atlas.missing_expression, atlas.missing_operator, atlas.missing_commaErrorAn expression or argument list is missing an operand, operator, or comma at the highlighted location.
atlas.unexpected_operator, atlas.unexpected_tokenErrorAn operator/value appears where the current expression cannot accept it. Check the neighboring operands and separators.
atlas.add_open_braceWarningAn event or control-flow header has no visible opening block brace. Add {.
atlas.unexpected_semicolonErrorA semicolon separates an event/control-flow header from its block. Remove the semicolon before {.
atlas.missing_declaration_nameErrorA declaration type is followed by =, ;, [, or ( instead of a name.
atlas.unexpected_parameterErrorA parameter is missing its name or contains unsupported punctuation/trailing tokens. Use one optional type plus one name.
atlas.use_event_syntax, atlas.unsupported_gpcErrorThe source resembles Python/GPC def, main, combo, wait, get_val, or set_val. Rewrite it with Atlas events and APIs.
atlas.unsupported_for_inErrorA 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 codeSeverityMeaning and correction
atlas.unknown_eventErrorThe callback name is not one of on_start, on_connect, on_frame, on_input, or on_stop.
atlas.invalid_event_parametersErrorAn event other than on_input declares parameters. Native validation uses atlas.event_parameters.
atlas.missing_callbackInfoNo runnable on_connect, on_frame, or on_input block exists. Add the event that should perform work.
atlas.event_object_unavailableErrorCode expects an event.* packet object. Read controller state from input and write through output.
atlas.missing_argument, atlas.too_many_argumentsErrorA built-in call does not match its minimum/maximum argument count. Native validation groups these under atlas.argument_count.
atlas.argument_rangeWarningA known numeric literal is outside the documented pressure, axis, color, coordinate, byte, player, or unit range.
atlas.not_callableErrorA known property/member is followed by (...) even though it is not a method. Native validation reports the same code.
atlas.readonly_apiErrorCode assigns a read-only built-in property. Native validation may report atlas.readonly_member.

Names, constants, and configuration guidance

Editor codeSeverityMeaning and correction
atlas.unknown_button, atlas.unknown_trigger, atlas.unknown_stick, atlas.unknown_rumble_motorErrorA controller name is not recognized for that argument. Use the API reference's canonical names.
atlas.unknown_colorWarningAn 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_colorErrorA 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_fieldErrorAn 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>ErrorA bare controller/ADT name needs the qualified spelling provided after the colon.
atlas.quote_literal:<name>ErrorA name-like string argument lacks quotes. Use the quoted suggestion carried after the colon.
atlas.backend_constant:vision.<backend>ErrorA vision backend was written as a string. Use the suggested vision.* constant.
atlas.replace_button:<preferred-name>InfoA compatibility button name works, but the suffix supplies the simpler canonical Atlas name.
atlas.renamed_api:<new-name>ErrorThe 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_branchErrorA 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_modelWarningA literal models.path(name) has no matching two-argument models.set(name, path) registration.
atlas.model_profileInfoA 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_variableInfoA 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 useReason 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 nameAtlas 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 declarationsUse var for whole and decimal numbers. type() may still report int32/float runtime categories.
handle name declarationshandle is a runtime result kind, not a declaration keyword. Consume or store a returned handle in a supported value flow.
sequence, yield, sleep, awaitNo sequence/coroutine scheduler exists. Keep state across event calls with globals and input.time/time_ms.
overlay.*Overlay behavior was merged into ui.*.
ui.createRemoved. Use current primitives such as ui.print, ui.rect, ui.line, ui.circle, and ui.status.
ui.formatUse string.format.
Plural vision helper namesUse the current singular typed helper, such as vision.color, vision.circle, or vision.target.
controller.ps5.r2controller.ps5 is a terminal family constant. Use ps5.r2 as a name and input.get(ps5.r2) for pressure.
Controller APIs inside helper functionsValidation is lexical. Read/apply directly in on_input and pass scalar values to helpers.
& at a shared-struct call siteDeclare Settings &settings, then call edit(settings).
Scientific notation and trailing-dot decimalsUse ordinary decimal literals such as 1000 and 1.0.
Foreach/for-in, bitwise, classes, lambdas, imports, exceptionsThese 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.

ConditionCurrent resultHow to prevent it
More than 40 active user callsScript 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 initializersScript 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 itselfStruct 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 rangeRead returns null; write does nothing.Validate index >= 0 && index < array.count().
Division or remainder by zeroProduces numeric 0.Check the divisor first rather than treating 0 as a meaningful quotient.
Unknown user call that remained only a warningProduces null.Treat unknown-function warnings as errors in practice.
count() on a non-arrayProduces 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_sendThe 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_stopReturns 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 packetReturns 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.

These are compatibility notes, not recommended patterns. The examples and recipes elsewhere in this guide stay inside the source-verified, tested subset.
  1. 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.
  2. Duplicate event severity differs. Native analysis warns and the last handler wins; Monaco may report an error. Keep exactly one handler per event.
  3. on_input(input, output) names are decorative compatibility syntax. The compiler does not create event-parameter locals; the names work because input/output are built-in roots.
  4. Shared struct parameters share the object, not the caller slot. Field writes affect the caller; replacing the whole parameter changes only the callee binding.
  5. Only explicitly typed struct parameters deep-copy. Passing a struct through an untyped parameter does not request the recursive copy.
  6. Other heap-backed values retain shared payloads. Arrays, fonts, models, targets, vision tools, and handles are not recursively copied by ordinary parameter passing.
  7. Scalar type enforcement is incomplete. Several declarations are checked, but later plain assignments are not uniformly validated. Keep values type-correct by design.
  8. An uninitialized bool is null. It is falsey, but type(value) reports null until a bool is assigned. Initialize bools explicitly.
  9. Const purity is conservative but not a full constant proof. Calls are rejected, yet every identifier/property dependency is not folded and proven.
  10. 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.
  11. Prefix/postfix updates share updated-value behavior. Do not depend on C-style old-value postfix semantics.
  12. Member ++/-- lowering is incomplete. Use compound assignment on a member instead.
  13. 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.
  14. Duplicate function and enum type names lack complete native diagnostics. Declare each once.
  15. Hex validation is incomplete for a bare 0x. Always include at least one hexadecimal digit.
  16. A dynamic fractional index is rounded by the VM. The analyzer rejects a fractional literal but cannot prove every dynamic value. Keep indices whole.
  17. 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.

validation-friendly.atlas
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

  1. Start at the earliest error: correct missing quotes, parentheses, brackets, braces, or semicolons before reading later messages.
  2. Check the declaration: confirm every name exists, is in scope, is not a keyword, and uses a current type spelling.
  3. Check the event: move physical controller APIs directly into on_input and video/UI work into the appropriate frame path.
  4. Check the value shape: fully subscript arrays, verify struct fields, use enum ::, and match typed vision values to their creator.
  5. Check the call: match argument count, supply compatible values, consume results, and return one compatible kind on every path.
  6. Check sharing intent: explicitly type struct parameters and distinguish Struct &parameter from var alias = &target.
  7. Resolve warnings: unknown calls, duplicate events, unused results, and non-array count() often indicate real no-op behavior.
  8. 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.

Events

Match work to the lifecycle callback and legal API context.

API Reference

Confirm current methods, signatures, result kinds, members, constants, and controller names.

Atlas diagnostics reference. Codes, severities, corrections, runtime guards, and caveats are reviewed against the native lexer, parser, analyzer, compiler, VM, and automated tests.