Diagnostics
Every message FantASM prints carries a level, a code and a position.
Reading one
Error [E1003]: Undefined label or constant: `nowhere_at_all`
src/main.asm:12:6
jp nowhere_at_all
^Erroris the level.[E1003]is the level’s letter and the code. The letter matters — see below.src/main.asm:12:6is file, line, column.- The source line is quoted with a caret under the column, so you do not have to count.
Some diagnostics add more:
Hint: use @NAME to reach a constant outside this moduleA hint says what to do about it. A note on a second location points at the other half of the problem — where a label was first defined, say, when you have defined it twice.
⛔ A diagnostic without a file:line is about the project file, not your source. The fault is in how fantasm.toml’s tables relate rather than at a point in any text, so there is no line to point at.
Levels
| Shown | Meaning |
|---|---|
Error | The build failed. Nothing is written. |
Fatal Error | The build failed and could not continue far enough to look for more problems. |
Warning | Assembled, but something is probably wrong. |
Info | Progress and detail, shown with -v. |
Message | Your own message directive. |
The same code number can carry different levels. 1012 is a warning when a value is truncated to 16 bits and an error when the same value cannot be used at all. The level is decided where the diagnostic is raised, which is why the letter is printed and not just the number.
One number, one meaning. 1049 and 1060 each named two unrelated diagnostics, told apart only by the level letter — so looking one up found whichever entry came first. The address error moved to 1082 and the NEX entry-point warning to 1083; the two numbers now mean what most people already thought they meant.
Asking for more warnings
-W turns on the unused-label sweep and nothing else. Every other warning is shown whether or not you pass it.
fantasm build src/main.asm -Wor in fantasm.toml:
[assembler]
warnings = trueW1049 unused label does not fire for a label that is KEEP-pinned, GLOBAL-exported, discarded by --gc-modules, or run into by the code above it — in none of those cases is there anything to act on.
Meeting the common ones
E1003 Undefined label or constant. A typo, a missing INCLUDE, or a name you expected to reach out of a MODULE. Constants do not fall back to global scope from inside a module — use @NAME.
E1004 File not found. Check include_dirs. If the missing file is another target’s output, you get E1078 instead, which is more useful — see Building Several Images.
E1005 Syntax error and E1008 Invalid instruction. Usually a mnemonic that does not exist in the form you wrote it, or an operand the instruction cannot take. Both quote what they found.
E1013 Attempt to redefine label or constant. The note points at the first definition.
E1016 Z80n extended instructions are not enabled. Set target = "zxnext", or z80n = true for a Z80N program on another machine.
E1036 Maximum code size exceeded. max_code_size limits how much code there is, not the address it reaches — a program ORGed at $8000 emitting 2 KB has used 2 KB of the budget. zx16 additionally refuses anything above $8000.
W1068 Code emitted in ROM and W1069 Code assembled before any ORG. Both usually mean a code-bearing INCLUDE sits above your ORG. Anything emitted before an origin lands at $0000.
E1060–E1063 Reserved word. A macro name, macro parameter or module name cannot be a word the tokeniser has already claimed — see below.
E1075 This is a string, which has no numeric value. __NAME__ and friends carry text. db __NAME__ assembles it; ld a, __NAME__ cannot.
E1200 Rhai error. A !rhai block failed to compile, or the engine ran into a fault. The position points inside the script, at the line you wrote rather than at the !rhai that opened it. What a script says on purpose — ctx.warn, ctx.error — is 1080 instead, in the script’s own words.
Reserved words
A macro name, a macro parameter name and a module name must be words the tokeniser has not already claimed. Every word below produces a keyword token instead, so using one raises E1060, E1061 or E1062.
A label may be named after any of these, and a constant after a directive: org: is legal, KEEP org pins it, and hex equ 9 defines a constant called hex. A register or condition name cannot be a constant — a equ 5 is E1005.
| Family | Words |
|---|---|
| Directives | org include binary incbin message db defb byte dw defw word ds block dh hex opt macro end endm dz if ifdef ifndef else endif global enum ende struct ends nex bank page slot sna target format module endmodule keep test endtest init_reg init_mem assert_reg assert_mem assert_cycles rhai |
| Opcodes | every Z80 and Z80N mnemonic — ld, nop, jr, mul, … |
| Registers | a b c d e h l i r bc de hl sp ix iy af ixh ixl iyh iyl |
| Conditions | nz z nc c po pe p m |
| Operators | equ |
| Options | verbose cspect z80n maxcodesize case_insensitive target format |
| Booleans | on off true false yes no |
Matching is case-insensitive, so Slot and SLOT are reserved too.
⛔ This is the first thing to check when a name behaves strangely. A module called A or a macro parameter called c is a register name, and the diagnostic that results rarely mentions registers. It costs nothing to rule out and saves a long search when it is the cause.
Every code
The message text is what FantASM prints; … stands for a name, file or value it fills in.
| Code | Message |
|---|---|
1001 | Address overflow, PC > 65535 |
1002 | Invalid character in label |
1003 | Undefined label or constant: … |
1004 | File not found: … |
1005 | Syntax error… |
1006 | Bad constant definition |
1007 | Invalid register pair |
1008 | Invalid instruction… |
1009 | Integer out of range |
1010 | Address is out of range, the value has been truncated |
1011 | Integer has been truncated to 8 bits |
1012 | Integer has been truncated to 16 bits |
1013 | Attempt to redefine label or constant |
1014 | Unexpected end of line |
1015 | Invalid condition |
1016 | Z80n extended instructions are not enabled |
1017 | Unexpected closing parentheses |
1018 | Unclosed parentheses |
1019 | CSpect pseudo ops are not enabled |
1020 | Invalid assembler option: … |
1021 | Invalid number or expression |
1022 | Invalid Hexadecimal string |
1023 | Bit number is out of range will and will be truncated |
1024 | Source file previously included |
1025 | Discarded extra characters at and of line |
1026 | Encountered END without MACRO directive |
1027 | ENDIF without IF |
1028 | ELSE without IF |
1029 | Invalid or missing macro name, found … |
1030 | Comma expected |
1031 | Invalid or missing macro parameter name, found … |
1032 | Macros may not be nested |
1033 | Incorrect number of macro parameters |
1034 | Only local labels are permitted inside macros |
1035 | Macro already defined |
1036 | Maximum code size exceeded |
1037 | SizeOf cannot be determined |
1038 | String contains non-ascii characters… |
1039 | Invalid 8-bit register |
1040 | ENUM name expected |
1041 | ENDE without ENUM |
1042 | Enum member name is invalid |
1043 | Enum step value cannot be zero |
1044 | STRUCT name expected |
1045 | ENDS without STRUCT |
1046 | STRUCT member name is invalid |
1047 | STRUCT member size suffix is invalid |
1048 | STRUCT already defined |
1049 | unused label … (a warning, from -W) |
1050 | Invalid directive |
1051 | Informational text, shown with -v |
1052 | Unknown SNA command: … |
1053 | Unknown NEX command: … |
1054 | Expected NEX command, found: … |
1055 | Expected SNA command, found: … |
1056 | Your own message directive |
1057 | Shebang detected and ignored: … |
1058 | General error: … |
1059 | Memory region overlap detected |
1060 | … is a reserved word and cannot be a macro name |
1061 | … is a reserved word and cannot be a macro parameter name |
1062 | … is a reserved word and cannot be a module name |
1063 | Invalid or missing module name, found … |
1064 | ENDMODULE without MODULE |
1065 | MODULE … was never closed with ENDMODULE |
1066 | Invalid or missing label after KEEP, found … |
1067 | KEEP names …, which is not defined |
1068 | Code emitted at … is in ROM and cannot run |
1069 | Code assembled at …, before any ORG set an origin |
1070 | Invalid or missing name after GLOBAL, found … |
1071 | GLOBAL names …, which is not defined |
1072 | Unknown escape \… in a string or character literal |
1073 | A size computed from $ was settled at …, but the line was placed at … |
1074 | … was never closed |
1075 | … is the string “…”, which has no numeric value |
1076 | A digit separator must be _, not ' — found after … |
1077 | Targets depend on each other in a cycle: … |
1078 | … not found. It is the output of target …, which … does not list in depends |
1079 | … is a macro; ifdef and ifndef test constants and cannot see one |
1080 | What a script said through ctx.warn or ctx.error, in its own words |
1081 | What a script printed — twenty lines a block, then a count of the rest |
1082 | Invalid address or bank (was 1049, which the unused-label warning kept) |
1083 | NEX entry point … has no code (was 1060, which the reserved-word error kept) |
1084 | … is referenced only by a !test block and has been discarded by --gc-modules |
1200 | A Rhai script failed to compile, or the engine raised a fault running one |