When a program refuses to compile or to upload, the IDE shows an error message. At first glance it looks cryptic, but it follows a logic: it gives the file, the line, and the nature of the problem. Learning to read it means gaining your independence — sorting yourself out rather than staying stuck, or copying the error into a search engine without understanding it. The vast majority of a beginner’s errors come down to four or five recurring kinds.

Note

Which board? The messages quoted here are those of the Arduino AVR build chain (Uno, Mega, Nano) as shown by IDE 2.x. On an ESP32 or a Teensy, the language error messages are very close (the same compiler from the GCC family), but the ones tied to uploading differ. The reading reflex itself is the same everywhere.

What is it for?

Getting stuck on an error wastes a huge amount of time when you cannot read it, and getting unstuck is almost always the same handful of causes. Knowing where to look (the line number), what to start with (the first error, not the last) and what the common messages mean turns a wall into a simple checklist.

Compiling or uploading: two families

We saw it in how a program runs: compiling and uploading are two separate steps, so two families of errors.

  • Compilation error: turning the code into binary fails. It is a code problem (syntax, name, type). The message comes from the compiler.
  • Upload error: the code compiled, but sending it to the board fails. It is a link problem (port, cable, board). The message comes from the sending tool (avrdude on AVR).

Knowing which family you are dealing with already points the way: reread the code, or check the connection.

Anatomy of a compilation message

A compilation error message has a regular shape:

sketch.ino: In function 'void loop()':
sketch.ino:7:16: error: 'led' was not declared in this scope
    7 |   digitalWrite(led, HIGH);
      |                ^~~

You read there, in order: the file and the function concerned (loop()), then file:line:column (here line 7, column 16), the word error:, the description, and the offending line of code copied out with its number in a gutter. The ^ points at the exact word causing the problem, here led and not the function call. Two reflexes:

  • start with the FIRST error. One mistake often drags others along in a cascade. Fix the first one, recompile, and the following ones often disappear;
  • go and look at the line given — bearing in mind that some errors (a missing ;, for one) are reported on the next line.

Tip

Do not copy the message out by hand. When compilation fails, IDE 2.x shows a notification at the bottom right with a COPY ERROR MESSAGES button: one click puts the whole message on the clipboard, ready to paste into a search engine or into a question to a classmate.

Notice in passing that the same message appears three times — spelled out in the Output panel, summarised on its last line, and repeated in the notification. That is one single error, not three.

Output panel of the Arduino IDE 2.x at the bottom of the window, showing a compilation error in red spelled out over several lines, and at the bottom right a notification carrying a COPY ERROR MESSAGES button.|640

The most common compilation errors

expected ';' before .... A semicolon is missing, almost always on the line before the one given.

'xxx' was not declared in this scope. A name (variable, function) is used without having been declared: a typo, a forgotten #include, a variable declared further down, or a local variable used outside its scope (see local and global variables).

fatal error: xxx.h: No such file or directory. A header file cannot be found: a library that is not installed, a misspelled name, or a missing dependency of a library that is installed (see using a library). The word fatal means compilation stops straight away: unlike the others, this error never comes in a cascade. It is on its own, and it is the only one to deal with.

expected '}' at end of input. An opening brace was never closed. Check that the { } balance out (the IDE’s auto-indent, Ctrl+T, helps to spot them).

redefinition of 'xxx'. The same variable is declared twice in the same scope.

invalid conversion from ... to .... An incompatible type is passed where another is expected (see typing variables).

Tip

Warning ≠ error. The compiler tells warnings (warning:) apart from errors (error:). A warning flags something suspicious but does not stop you compiling and uploading (a variable declared but never used, for instance). An error blocks. Do not mix the two up: you can ignore a warning while you get on with things, never an error.

Common upload errors

avrdude: stk500_recv(): programmer is not responding. The board did not answer: the wrong port selected, a charge only cable, or a board that is not recognised. See the troubleshooting in getting started.

Port busy or locked. Another application (a serial monitor left open elsewhere, PlatformIO) is holding the port: close the other window and try again.

Messages to decode

Rather than a sketch to read, here are three real errors to diagnose — the code, the message as the IDE shows it, the reading.

Case 1 — the forgotten semicolon. The code:

void setup() {
  pinMode(2, OUTPUT);
}
 
void loop() {
  digitalWrite(2, HIGH)
  delay(1000);
  digitalWrite(2, LOW);
  delay(1000);
}

The message:

Blink.ino: In function 'void loop()':
Blink.ino:6:24: error: expected ';' before 'delay'
    6 |   digitalWrite(2, HIGH)
      |                        ^
      |                        ;
    7 |   delay(1000);
      |   ~~~~~
exit status 1

Compilation error: expected ';' before 'delay'

The reading: the error is reported on line 6, column 24, and column 24 is the character that comes immediately after the closing bracket. The compiler is pointing at the emptiness, where it expected something. It even goes as far as drawing the missing ; on the line below. The ~~~~~ under delay marks the word that tripped it up: it read digitalWrite(2, HIGH) then delay, with no separator between the two. This is the classic semicolon trap: the mistake is at the end of the previous line, even when the message points at the next one.

Case 2 — the variable out of scope. The code:

void setup() {
int my_age = 18;
Serial.begin(115200);
 
}
void loop() {
Serial.print(my_age);
}

The message:

Blink.ino: In function 'void loop()':
Blink.ino:7:14: error: 'my_age' was not declared in this scope
    7 | Serial.print(my_age);
      |              ^~~~~~
exit status 1

Compilation error: 'my_age' was not declared in this scope

The reading: my_age does exist, it is declared on line 2, and yet the compiler says it does not. That is the trap: it is declared inside setup(), so it is born and dies with it. By the time we are in loop(), the compiler no longer knows it. The message is not lying: in this scope, the name is not declared. The fix: move int my_age = 18; out of the braces, above setup(), to make it a global variable (see local and global variables).

This is the most misleading error of the lot to read, because the variable is right in front of you in the file. The reflex: do not look for whether the name exists, but in which block it was written.

Case 3 — the error that is not in your file. The code:

#include <Adafruit_BMP280.h>
void setup() {}
void loop() {}

The message:

In file included from Blink.ino:1:
...\libraries\Adafruit_BMP280_Library/Adafruit_BMP280.h:26:10: fatal error: Adafruit_Sensor.h: No such file or directory
   26 | #include <Adafruit_Sensor.h>
      |          ^~~~~~~~~~~~~~~~~~~
compilation terminated.

The reading: three lines of code, and the message points at a line 26 that does not exist on your machine. The In file included from is the key. It unrolls the chain: your sketch includes Adafruit_BMP280.h, which on its line 26 includes Adafruit_Sensor.h, which cannot be found. The library was indeed installed, but not its dependency (see using a library). Nothing to fix in the sketch: the library has to be reinstalled, accepting Install all.

The lesson goes beyond this case: the file named by an error is not necessarily yours. Before hunting for a mistake in your code, read the path.

Pitfalls

Jumping on the last error. When the list is long, it is the first one to read: the others often follow from it and evaporate once the first is fixed.

Fixing at random. Changing things without having read the message or the line piles new mistakes on top. Read first, understand, then fix.

Ignoring the line number. The message says where: file:line. It is the most useful piece of information, as long as you remember that a missing ; points at the line after.

Mixing up warning and error. See the box: a warning does not stop you uploading, an error does.

Exercises

Exercise 1 — Where is the mistake?

The compiler shows sketch.ino:3:3: error: expected ';' before 'delay'. Here is the code. Which line do you fix, and how?

void loop() {
  int etat = digitalRead(2)
  delay(10);
  digitalWrite(13, etat);
}

Exercise 2 — The unknown name

Message: error: 'tempo' was not declared in this scope. Give three possible causes and the fix for each.

Where it fits in the project

  • Step 4 of the proof of concept phase — on the first sketch of any length, compilation errors are unavoidable. Knowing how to read them is what makes the difference between getting on alone and staying stuck.
  • Integration and testing phase — when the subsystems come together, errors multiply. A methodical reading of the messages saves a considerable amount of time.

See also