Diagnostics
Every message FantASM prints carries a level, a code and a position.
Anatomy of a Diagnostic
Error [E1003]: undefined symbol `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 Levels.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:
help: `nowhere_at_all` is defined outside this module. Use `@nowhere_at_all`A 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.
Renumbered Codes
One number means one thing, and a code stands for one fault rather than a family. Two numbers each named two unrelated diagnostics and were told apart only by the level letter, so looking one up found whichever entry came first; four others covered several faults at once, so a [lint] entry or a search of a build log picked out a family rather than the fault meant.
| Was | Is now | |
|---|---|---|
1049 | 1082 | The address error moved; the unused-label warning kept the number. |
1060 | 1083 | The NEX entry-point warning moved; the reserved-word error kept the number. |
1020 | 1129, 1130, 1134, 1135 | A bad option name, a bad option value and an unknown output format. |
1008, 1005 | 1136, 1137 | What a device does not support. |
1058 | 1005, 1138, 1139, 1140, 1141, 1142 | Five faults and a test-failure count. |
Unused-Label Sweep
Syntax: fantasm build <source> -u
-u turns on that one sweep and nothing else. Every other warning is shown whether or not you pass it, and --no-find-unused turns off only the sweep. find_unused under [assembler] is the same setting in fantasm.toml.
fantasm build src/main.asm -u[assembler]
find_unused = trueIt was -W/--enable-warnings/--no-warnings and warnings until 2.0. Those still work, saying what replaced them once (W1103), and are withdrawn in 2.1.
W1049 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.
Nor for any part of a STRUCT instance something touches. An instance is one object’s layout, so a reference to a member marks the instance and vice versa: ld hl,inst and then indexing through (hl) uses every field without naming one. Deleting a member to answer a warning would move the fields after it, so there is no change to make. An instance nothing touches at all is still reported.
Common Codes
The elaboration below is present where the message alone leaves something unanswered. Every code is in Code Reference.
E1003 undefined symbol …
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. A missing file that is another target’s output is E1078 instead, which says so — see Building Several Images.
E1005 syntax error: …
The line stopped making sense. Where it can say more it adds it after the colon; a bare syntax error means there was nothing useful to name.
E1008 invalid instruction: …
A mnemonic that does not exist in the form you wrote it, or an operand the instruction cannot take.
E1013 … is already defined
The note points at the first definition.
E1016 Z80N instructions are not enabled
Set device = "zxnext", or z80n = true for a Z80N program on another machine. The hint says the same in directive form.
E1020 unknown assembler option …
The name after !opt. A value that option will not take is E1134, and an output format this build does not write is E1135; both name what is actually wrong rather than an option that was fine.
E1036 code size limit 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. The hint says which of the two limits was reached.
E1058 General error: …
Nothing in a source file raises it. It stood for a --test run’s failure count, an empty test body, a body with nowhere to go, a !rhai block missing its brace and two fantasm.toml target faults; those are E1138, E1139, E1140, E1005, E1141 and E1142.
E1060 … is a reserved word and cannot be a macro name
E1061 … is a reserved word and cannot be a macro parameter name
A macro’s name and its parameters cannot be words the tokeniser has already claimed — see Reserved Words. E1063 is the neighbouring case of a missing or malformed MODULE or !library name.
E1075 … is a string and cannot be used as a number
__NAME__ and friends carry text. Example: db __NAME__ assembles it, and ld a, __NAME__ is this.
W1068 code at … is in ROM on …
W1069 code at … assembled before the first ORG
Both usually mean a code-bearing INCLUDE sits above your ORG. Anything emitted before an origin lands at $0000.
E1200 Rhai function … failed: …
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’s name and its parameters must be words the tokeniser has not already claimed. Every word below produces a keyword token instead, so using one there raises E1060 or E1061.
Position decides everywhere else, and most slots take these words happily. A label may be named after any of them, and so may a STRUCT member, an ENUM member or type, a MODULE and a !library: org: is legal, KEEP org pins it, hex equ 9 defines a constant called hex, and Device db is a struct member. A register or condition name still cannot be a constant — a equ 5 is E1005.
assert and debug are in this table like any other directive, and like any other they can still name a label, a STRUCT member and the rest: DEBUG equ 1 with ld b,DEBUG and IFDEF DEBUG all work.
| Family | Words |
|---|---|
| Directives | org include binary incbin message db defb byte dw defw word ds block rs section align dh hex opt macro end endm dz if ifdef ifndef else endif global extern enum ende struct ends nex bank page slot sna device target format module endmodule library interface endinterface keep test endtest init_reg init_mem init_cycle_limit assert assert_reg assert_mem assert_cycles assert_checksum debug watch rhai rep endr virtual endvirtual |
| 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 device target format |
| Booleans | on off true false yes no |
Matching is case-insensitive, so Slot and SLOT are reserved too.
E1062 is withdrawn. It refused a module or library named after a reserved word, which is now allowed. device joined this table in 2.0 and costs a struct nothing, a member being read only as Type.member. target is here only while !target is still accepted, and leaves in 2.1.
⚠ 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.
Code Reference
The message text is what FantASM prints; … stands for a name, file or value it fills in.
| Code | Message |
|---|---|
1001 | address overflow: PC past $FFFF |
1002 | invalid character in label … |
1003 | undefined symbol … |
1004 | file not found: … |
1005 | syntax error: … |
1006 | invalid constant definition |
1007 | invalid register pair |
1008 | invalid instruction: … |
1009 | value … out of range |
1010 | address $… truncated to $… |
1011 | value … truncated to 8 bits ($…) |
1012 | value … truncated to 16 bits ($…) |
1013 | … is already defined |
1014 | unexpected end of line |
1015 | invalid condition … |
1016 | Z80N instructions are not enabled |
1017 | unmatched ) |
1018 | unclosed ( |
1019 | CSpect pseudo-ops are not enabled |
1020 | unknown assembler option … |
1021 | invalid expression |
1022 | invalid hex string … |
1023 | bit number … out of range 0..7 |
1024 | circular include: … |
1025 | extra characters at end of line: … |
1026 | ENDM without MACRO |
1027 | ENDIF without IF |
1028 | ELSE without IF |
1029 | expected a macro name, found … |
1030 | expected , |
1031 | expected a parameter name, found … |
1032 | nested MACRO definition |
1033 | macro … takes … parameters, but … were given |
1035 | macro … is already defined |
1036 | code size limit exceeded |
1037 | cannot determine the size of … |
1038 | non-ASCII character in string… |
1039 | expected an 8-bit register |
1040 | expected a name after ENUM |
1041 | ENDE without ENUM |
1042 | invalid ENUM member name … |
1043 | ENUM step cannot be zero |
1044 | expected a name after STRUCT |
1045 | ENDS without STRUCT |
1046 | invalid STRUCT member name … |
1047 | invalid size for STRUCT member … |
1048 | STRUCT … is already defined |
1049 | unused label … (a warning, from -u) |
1050 | unknown directive … |
1052 | unknown !sna option … |
1053 | unknown !nex option … |
1054 | expected a !nex option, found … |
1055 | expected a !sna option, found … |
1056 | Your own message directive |
1057 | shebang line ignored |
1058 | General error: … — nothing in a source file raises it; see 1005 and 1138–1142 |
1059 | address $… in bank … has already been written |
1060 | … is a reserved word and cannot be a macro name |
1061 | … is a reserved word and cannot be a macro parameter name |
1063 | expected a name after MODULE, found … |
1064 | ENDMODULE without MODULE |
1065 | unterminated MODULE … |
1066 | expected a label after KEEP, found … |
1067 | undefined symbol … in KEEP |
1068 | code at … is in ROM on … |
1069 | code at … assembled before the first ORG |
1070 | expected a name after GLOBAL, found … |
1071 | undefined symbol … in GLOBAL |
1072 | unknown escape sequence \… |
1073 | size computed from $ at …, but the line was placed at … |
1074 | unterminated … |
1075 | … is a string and cannot be used as a number |
1076 | invalid digit separator ' after … |
1077 | circular dependency between targets: … |
1078 | … not found: it is written by target …, which … does not depend on |
1079 | ifdef cannot test macro … |
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 … (was 1049, which the unused-label warning kept) |
1083 | NEX entry point … contains no code (was 1060, which the reserved-word error kept) |
1084 | … is only referenced from a !test block and was removed by --gc-modules |
1085 | output is not contiguous: $…..$… spans … bytes but … were emitted |
1086 | … evaluated to … before its MODULE body was placed, and is now … |
1087 | IF condition evaluated to … before the MODULE body was placed, and is now … |
1088 | undefined Rhai function … |
1089 | … is a label and cannot be used in !opt |
1090 | Rhai function … in … shadows the definition in … |
1091 | A !test assertion did not hold: what it checked, and what it found |
1092 | … cannot be relocated (relocatable output only) |
1093 | unknown instruction, directive or macro … |
1094 | … at column 0 defines a label, not a macro call |
1095 | !library must be at the top level of its file |
1096 | library … is already declared in … |
1097 | INTERFACE must be at the top level of a library |
1098 | duplicate INTERFACE in library … |
1099 | ENDINTERFACE without INTERFACE |
1100 | INTERFACE of library … lists undefined symbol … |
1101 | … is private to library … |
1102 | --reloc requires a single-segment bin image: … |
1103 | … is deprecated; use … (the old spelling still works, and leaves in 2.1) |
1104 | test … did not halt within … T-states |
1105 | unknown option … for …: expected one of … |
1106 | duplicate option … on … |
1107 | cannot mix positional and name=value arguments on … |
1108 | expected an option name for …: one of … |
1109 | … requires … |
1110 | … and … cannot both be given on … |
1111 | span … is outside physical memory (… bytes) |
1112 | span … runs past the end of … (… bytes) |
1113 | second ELSE for one IF |
1114 | invalid NEX version …: expected V1.2 or V1.3 |
1115 | NEX V1.2 was requested, but … requires V1.3 |
1116 | macro … exceeds the nesting limit of 64 |
1117 | !nex screen is not supported |
1118 | STRUCT … cannot contain itself |
1119 | unknown member type … |
1120 | … is ignored without an SLD file |
1121 | block size … out of range 0..65536 |
1122 | … outside a !test block |
1123 | index displacement … out of range -128..127 |
1124 | unknown key … in fantasm.toml |
1125 | REP repeats an instruction, and … is not one |
1126 | REP count … out of range 0..65536 |
1127 | expected , after the REP count |
1128 | ENDR without REP |
1129 | unknown device … |
1130 | … has 16K banks, not 8K pages |
1131 | unknown diagnostic code … in [lint] |
1132 | [lint] … is not configurable |
1133 | invalid level … for [lint] …: expected allow, warn or deny |
1134 | invalid value … for option … |
1135 | unknown output format … |
1136 | … is not supported on … |
1137 | bank takes no slot on … (a 16K bank has one window) |
1138 | … tests failed — the count that fails the build, at the first failure |
1139 | test … has an empty body |
1140 | no room for test … above the program |
1141 | unknown target … |
1142 | target … depends on unknown target … |
1143 | !endvirtual without !virtual |
1144 | … is not allowed inside a !virtual block |
1145 | nested !virtual block |
1146 | !virtual cannot be used with --reloc |
1147 | invalid IF condition … |
1148 | ALIGN … is not a power of two, rounded up to … |
1149 | output was not written in address order |
1150 | … takes no value |
1151 | … requires a value |
1152 | expected a section name, found … |
1153 | conflicting options on section …: … |
1154 | SECTION is not allowed inside a MODULE |
1155 | ORG is not allowed inside a SECTION |
1156 | EXTERN requires object output |
1157 | expected a symbol name after EXTERN, found … |
1158 | … is not allowed inside a SECTION |
1159 | … cannot be used with object output |
1160 | cannot determine the page of … |
1161 | labels file … is stale: … has been rebuilt since it was written |
1162 | labels file … names …, which cannot be read |
1163 | … is not allowed in an object file |
1164 | !test is not allowed in an object file |
1165 | undefined reference to … in … |
1166 | multiple definition of … in … and … |
1167 | … and … were assembled for different devices |
1168 | cannot read object file …: … |
1169 | section … uses placement rule …, which is not supported |
1170 | no space for section … (… bytes) |
1171 | section … extends … bytes past $FFFF |
1172 | section … is … bytes larger than a page |
1173 | section … crosses from page … into page … without straddle |
1174 | section … at $… overlaps a section at $… |
1175 | section … at $… is in ROM |
1176 | relocation … against … out of range: … |
1177 | cannot resolve relocation … against …: … |
1179 | … in page … has no window and cannot be called from page … |
1200 | Rhai function … failed: … |