Scala 3 Module 1 – Start here: Scala 3.9 LTS on the JVM
Read Scala compiler errors and warnings
Read a Scala 3 diagnostic from its code, position and Found and Required types, fix common errors at the cause, and use -explain, -Wunused:all and -Werror.
What you will learn
- Read a Scala 3 diagnostic from its code, file position, caret and Found and Required types
- Fix the cause of errors E007, E171 and E172 rather than the symptom
- Explain why warning E029 lets the build pass and how -Werror makes it fail
- Use -explain, -deprecation, -feature and -Wunused:all to see what the compiler holds back
- Find a diagnostic's code in the Scala 3 Reference and fix the first error first
Before you start
What you’ll learn · Before you start
What you will learn
- Read a Scala 3 diagnostic from its code, file position, caret and Found and Required types
- Fix the cause of errors E007, E171 and E172 rather than the symptom
- Explain why warning E029 lets the build pass and how -Werror makes it fail
- Use -explain, -deprecation, -feature and -Wunused:all to see what the compiler holds back
- Find a diagnostic's code in the Scala 3 Reference and fix the first error first
Before you start
On this page
A Scala 3 error message names a code, a place and two types: [E007] Type Mismatch Error on line 2, column 25,
Found: ("4250" : String), Required: Long. Read in that order, most messages tell you what to change before you even
look at the code.
This lesson takes one message apart, fixes three common errors at their cause, shows a warning that compiles and then crashes the program, turns on the flags that reveal what the compiler holds back, and ends with a broken receipt for you to repair.
A diagnostic names a code, a place and two types
Every message the compiler prints about your code is a diagnostic: A message from the compiler about the source: an error, which stops the build, or a warning, which does not. Scala 3 diagnostics carry a code such as E007.: an error, which stops the build, or a warning, which does not. Here is a three-line program with one mistake, a number written as text:
@main def checkout(): Unit =
val totalCents: Long = "4250"
println(totalCents) The session compiles it twice, the second time with -explain. Like every session of this track it uses
--server=false, so the messages appear exactly as the compiler writes them; the Scala CLI documentation notes that
the compile server at times gets in the way of the full compiler output. The session also shortens the file’s full
path to its name:
from session import run
# One type error, first as the compiler reports it, then with the longer explanation that -explain adds.
run("""
cd errors
!scala compile Mismatch.scala --server=false
!scala compile Mismatch.scala --server=false -explain
""") Output
$ cd errors
$ scala compile Mismatch.scala --server=false
-- [E007] Type Mismatch Error: Mismatch.scala:2:25
2 | val totalCents: Long = "4250"
| ^^^^^^
| Found: ("4250" : String)
| Required: Long
|
| longer explanation available when compiling with `-explain`
1 error found
Compilation failed
[exit status 1]
$ scala compile Mismatch.scala --server=false -explain
-- [E007] Type Mismatch Error: Mismatch.scala:2:25
2 | val totalCents: Long = "4250"
| ^^^^^^
| Found: ("4250" : String)
| Required: Long
|-----------------------------------------------------------------------------
| Explanation (enabled by `-explain`)
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| Tree:
|
| "4250"
|
| I tried to show that
| ("4250" : String)
| conforms to
| Long
| but none of the attempts shown below succeeded:
|
| ==> ("4250" : String) <: Long
| ==> String <: Long = false
|
| The tests were made under the empty constraint
-----------------------------------------------------------------------------
1 error found
Compilation failed
[exit status 1]
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 mismatch_session.py
Read the first message from the top: the code and the kind of problem, the file with its line and column, the line
itself with a caret under the part that is wrong, then the two types. Found is the type of what you wrote, here the
literal "4250", shown as ("4250" : String): the type of exactly that string, which is a String. Required is the type the
place needs, Long, because totalCents was declared as one. The fix follows from the two lines: write the number,
4250, or declare a String if you meant text. The last lines count the problems and say the build failed.
-explain adds the compiler’s reasoning: it tried to show that ("4250" : String) conforms to Long, that is, that a
String can be used where a Long is needed, and every attempt failed. For a plain mismatch the short message is
enough; for an error you do not understand, the explanation shows which comparison failed. Step through the parts of
the message in the order to read them:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- The code. [E007] names the kind of problem with a number you can look up in the Scala 3 Reference: E007 is Type Mismatch. Error means the build stops; a warning would say Warning.
- The place. Mismatch.scala:2:25 is the file, the line and the column where the problem starts. Editors turn this part into a link to that spot.
- The caret. The compiler prints line 2 and puts carets under "4250", the part it could not accept. The rest of the line was fine.
- Found. Found is the type of what you wrote. ("4250" : String) is the type of exactly that string, which is a String.
- Required. Required is the type the place needs. totalCents was declared as a Long, so it needs a Long. The fix is the difference between the two lines.
- The summary. The count of errors and Compilation failed close the output. With -explain, a longer explanation comes before them.
Key idea
Read a diagnostic in order: the code, the place, the caret, then Found against Required; the difference between the two types is usually the fix.
Checkpoint
Check: Reading a diagnostic
Fix the cause: a missing argument and a missing given
Two more errors appear in nearly every first week. The session below compiles a call with one argument too few, then a sort of a list whose element type has no ordering, then tries the import that the second message suggests, and finally runs the fixed program:
case class Price(cents: Long)
@main def cheapestFirst(): Unit =
val prices = List(Price(450), Price(120), Price(1599))
println(prices.sorted) from session import run
# A missing argument, a missing given, the import that the second message suggests, and the two fixes that work.
run("""
cd errors
!scala compile Arity.scala --server=false
!scala compile Ordering.scala --server=false
cd ../imported
!scala compile Ordering.scala --server=false
cd ../fixes
scala run CheapestFirst.scala --server=false
""") Output
$ cd errors $ scala compile Arity.scala --server=false -- [E171] Type Error: Arity.scala:4:19 4 | println(lineTotal(450)) | ^^^^^^^^^^^^^^ |missing argument for parameter quantity of method lineTotal: (unitCents: Long, quantity: Int): Long 1 error found Compilation failed [exit status 1] $ scala compile Ordering.scala --server=false -- [E172] Type Error: Ordering.scala:5:23 5 | println(prices.sorted) | ^ |No given instance of type Ordering[B] was found for parameter ord of method sorted in trait StrictOptimizedSeqOps. |I found: | | scala.math.Ordering.ordered[B]( | /* missing */summon[scala.math.Ordering.AsComparable[B]]) | |But no implicit values were found that match type scala.math.Ordering.AsComparable[B] | |where: B is a type variable with constraint >: Price |. | |The following import might make progress towards fixing the problem: | | import scala.math.Ordered.orderingToOrdered | 1 error found Compilation failed [exit status 1] $ cd ../imported $ scala compile Ordering.scala --server=false -- [E172] Type Error: Ordering.scala:7:23 7 | println(prices.sorted) | ^ |No given instance of type Ordering[B] was found for parameter ord of method sorted in trait StrictOptimizedSeqOps. |I found: | | scala.math.Ordering.ordered[B]((x: Price) => | scala.math.Ordered.orderingToOrdered[T](x)( | scala.math.Ordering.comparatorToOrdering[T]( | /* missing */summon[java.util.Comparator[T]]) | ) | ) | |But method orderingToOrdered in object Ordered does not match type scala.math.Ordering.AsComparable[B] | |where: B is a type variable with constraint >: Price |. 1 error found Compilation failed [exit status 1] $ cd ../fixes $ scala run CheapestFirst.scala --server=false List(Price(120), Price(450), Price(1599)) List(Price(120), Price(450), Price(1599))
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 causes_session.py
[E171], missing argument for parameter quantity, comes with the full signature of the method, so you can see
which parameter is missing and its type. [E172] is longer, but only its first line says what is wrong: No given instance of type Ordering[B] was found for parameter ord of method sorted, where B is any type above Price. In
plain words: sorted needs to know how to order prices, and nobody has said. The rest of the message is the
compiler’s search: what it tried, what was missing, and an import that “might make progress”. Here is what each of the
four errors of this lesson means, and the fix that removes its cause:
| Code and name | The usual cause | A fix that removes the cause |
|---|---|---|
| E007 Type Mismatch | Found is not Required: a value of the wrong type, often a number as text |
pass a value of the required type, or change the declared type |
| E171 Missing Argument | a call with fewer arguments than parameters | pass the argument, or give the parameter a default value |
| E172 Missing Implicit Argument | a method needs a given instance: A value that the compiler passes by itself to a parameter declared with using, chosen by its type. sorted, for example, needs a given Ordering for the element type. that nobody defined | define one, such as an Ordering, or call a method that takes the rule directly |
| E029 Pattern Match Exhaustivity, a warning | a match without a case for some value |
add the missing case |
// Two fixes for the missing Ordering: sort by a key, or give Price an ordering in its companion object.
case class Price(cents: Long)
object Price:
given Ordering[Price] = Ordering.by(_.cents)
@main def cheapestFirst(): Unit =
val prices = List(Price(450), Price(120), Price(1599))
println(prices.sortBy(_.cents))
println(prices.sorted) The fixed program shows both cures for E172: sortBy(_.cents) says how to order right where it sorts, and a given Ordering[Price] in the companion object of Price gives prices an ordering that every sorted finds, wherever it is
called. Both print the prices from cheapest to dearest.
Adding the import that the message suggests
The session added the import the message suggested, scala.math.Ordered.orderingToOrdered. The error stayed: the
compiler’s search only grew longer, and no import was suggested any more. Such imports only convert between kinds
of order that a type already has, such as an Ordering or a class that extends Ordered. Price has none, so give
it one, as the fixed program does.
Checkpoint
Check: Fixing E171 and E172 at the cause
A warning compiles, and can still crash the program
Warnings do not stop the build. Usually that is right, but some warnings predict a crash. This program charges a fee
for three ways to pay, and its match forgets one of them:
enum Payment:
case Card, Wallet, Cash
def feeCents(p: Payment): Long = p match
case Payment.Card => 30
case Payment.Wallet => 10
@main def fees(): Unit =
for p <- Payment.values do println(s"$p: ${feeCents(p)} cents") from session import run
# A warning that compiles: the build passes, the program crashes on the case the warning named, and -Werror stops it.
run("""
cd errors
scala compile Fees.scala --server=false
!scala run Fees.scala --server=false
!scala compile Fees.scala --server=false -Werror
cd ../fixes
scala run Fees.scala --server=false
""") Output
$ cd errors $ scala compile Fees.scala --server=false -- [E029] Pattern Match Exhaustivity Warning: Fees.scala:4:33 4 |def feeCents(p: Payment): Long = p match | ^ | match may not be exhaustive. | | It would fail on pattern case: Cash | | longer explanation available when compiling with `-explain` 1 warning found $ scala run Fees.scala --server=false -- [E029] Pattern Match Exhaustivity Warning: Fees.scala:4:33 4 |def feeCents(p: Payment): Long = p match | ^ | match may not be exhaustive. | | It would fail on pattern case: Cash | | longer explanation available when compiling with `-explain` 1 warning found Card: 30 cents Wallet: 10 cents Exception in thread "main" scala.MatchError: Cash (of class Payment$$anon$1) at Fees$package$.feeCents(Fees.scala:6) at Fees$package$.fees$$anonfun$1(Fees.scala:9) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1324) at Fees$package$.fees(Fees.scala:9) at fees.main(Fees.scala:8) [exit status 1] $ scala compile Fees.scala --server=false -Werror -- [E029] Pattern Match Exhaustivity Warning: Fees.scala:4:33 4 |def feeCents(p: Payment): Long = p match | ^ | match may not be exhaustive. | | It would fail on pattern case: Cash | | longer explanation available when compiling with `-explain` No warnings can be incurred under -Werror 1 warning found 1 error found Compilation failed [exit status 1] $ cd ../fixes $ scala run Fees.scala --server=false Card: 30 cents Wallet: 10 cents Cash: 0 cents
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 fees_session.py
The compile printed [E029] Pattern Match Exhaustivity Warning and named the value that no case covers, Cash, but it
ended with 1 warning found and status 0, so a build would pass. The run then printed the first two fees and crashed
on the third with scala.MatchError: Cash, the exact value the warning had named. -Werror turns every warning into an
error, No warnings can be incurred under -Werror, so the same mistake fails the build instead of the program. The
fixed version has a case for Cash and prints all three fees.
The match is an exhaustive match: A match with a case for every possible value of its type. When the compiler finds a value that no case covers, it warns with E029, and that value throws MatchError at run time. once it covers every value of Payment. For an
enum the compiler knows all the values, which is why it can name the missing one; when someone later adds a fourth way
to pay, the same warning names that one too. Step through the run that crashed, then the fix:
The drawing shows the whole scene; its 8 steps are listed below.
Every step as text
- The warning. The compiler finds that no case covers Payment.Cash and prints E029: match may not be exhaustive, it would fail on pattern case Cash.
- The build passes. A warning does not stop the build. The compile ends with 1 warning found and status 0, so a build script or CI would carry on.
- Card. The program loops over Payment.values. Card matches its case and prints 30 cents.
- Wallet. Wallet matches the second case and prints 10 cents.
- Cash. Cash matches no case. A match without a case for its value cannot return anything, so it throws.
- MatchError. The program stops with scala.MatchError for Cash, the very value the warning named, and exit status 1.
- The fix. fixes/Fees.scala gives Cash a case of its own, case Payment.Cash => 0. It compiles without a warning and prints all three fees, the last one Cash: 0 cents.
- With -Werror. Compiled with -Werror, the same warning becomes an error, No warnings can be incurred under -Werror, and nothing is built. The only way on is the fix, before any program can crash.
Silencing E029 with case _
Adding case _ => 0 makes the warning go away, and with it every future warning about this match: a fourth way to
pay added next year would cost nothing, without a word from the compiler. Name each value in its own case, as
fixes/Fees.scala does, and keep the warning working for you.
Checkpoint
Check: Warnings that predict a crash
Flags show what the compiler holds back
Some warnings appear only when you ask for them, and some arrive as a one-line summary until you do. The session compiles three small programs with and without the flag that shows each kind:
from session import run
# What the compiler holds back until a flag asks for it: unused values, deprecations and language features.
run("""
cd errors
scala compile Unused.scala --server=false
scala compile Unused.scala --server=false -Wunused:all
!scala compile Unused.scala --server=false -Wunused:all -Werror
scala compile Deprecated.scala --server=false
scala compile Deprecated.scala --server=false -deprecation
scala compile Conversion.scala --server=false
scala compile Conversion.scala --server=false -feature
""") Output
$ cd errors $ scala compile Unused.scala --server=false $ scala compile Unused.scala --server=false -Wunused:all -- [E198] Unused Symbol Warning: Unused.scala:2:6 2 | val taxPercent = 18 | ^^^^^^^^^^ | unused local definition 1 warning found $ scala compile Unused.scala --server=false -Wunused:all -Werror -- [E198] Unused Symbol Warning: Unused.scala:2:6 2 | val taxPercent = 18 | ^^^^^^^^^^ | unused local definition No warnings can be incurred under -Werror 1 warning found 1 error found Compilation failed [exit status 1] $ scala compile Deprecated.scala --server=false there was 1 deprecation warning; re-run with -deprecation for details 1 warning found $ scala compile Deprecated.scala --server=false -deprecation -- Deprecation Warning: Deprecated.scala:7:10 7 | println(total(List(450, 120))) | ^^^^^ |method total is deprecated since 2.0: use totalCents, which counts the discount 1 warning found $ scala compile Conversion.scala --server=false there was 1 feature warning; re-run with -feature for details 1 warning found $ scala compile Conversion.scala --server=false -feature -- Feature Warning: Conversion.scala:8:17 8 | println(charge(450)) | ^^^ |Use of implicit conversion given instance given_Conversion_Int_Cents should be enabled |by adding the import clause 'import scala.language.implicitConversions' |or by setting the compiler option -language:implicitConversions. |See the Scala docs for value scala.language.implicitConversions for a discussion |why the feature should be explicitly enabled. 1 warning found
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 flags_session.py
Without a flag, the unused value taxPercent passed in silence. -Wunused:all reports it as [E198] Unused Symbol Warning, unused local definition, and with -Werror that warning stops the build. The call to a deprecated method
first gave only the summary there was 1 deprecation warning; re-run with -deprecation for details; -deprecation
named the method, the version that deprecated it and the message its author left. The implicit conversion behaved the
same way: a summary, then with -feature the full warning, which says how to enable the feature on purpose.
| Flag | What it shows | When to use it |
|---|---|---|
-explain |
the reasoning behind a message, in more words | when a message is not clear |
-deprecation |
each use of a deprecated definition, with the version and its author’s note | always in CI, and before you upgrade |
-feature |
each use of a language feature that should be enabled explicitly | always |
-Wunused:all |
unused imports, local values, parameters and private members | in your own projects |
-Werror |
nothing new: it makes every warning an error | in CI, once the warnings are fixed |
On the command line, Scala CLI passes options that start with -W, and a few common ones such as -deprecation,
straight to the compiler; any other compiler option is written after -O. To keep them with the project, write them
in project.scala, for example //> using options -deprecation -feature -Wunused:all.
Key idea
Turn on -deprecation, -feature and -Wunused:all from the start, fix what they find, and then add -Werror in
CI, so that no warning reaches the main branch.
Checkpoint
Check: Flags that show more
Look up the code, then fix the first error first
The codes are there to be looked up. The Scala 3 Reference has a page for every code from E001 to E234, each with a sample that triggers it, the compiler’s real output and a fix; E007 is Type Mismatch, E029 Pattern Match Exhaustivity, E171 Missing Argument, E172 Missing Implicit Argument and E198 Unused Symbol. The pages describe the newest compiler, so a message on 3.9.0 can differ in its wording.
When there are several errors, start with the first. The compiler leaves out errors that would only follow from an earlier one, so fixing the first can bring others into view. This receipt has three mistakes, yet its first compile reports one; after that one is fixed, the next compile reports the other two:
// Fix the build: three mistakes stop this receipt from compiling. Each item is bought twice,
// and the receipt should print: 1140 cents for cake, tea
case class Item(name: String, cents: Long)
def lineTotal(item: Item, quantity: Int): Long = item.cents * quantity
@main def receipt(): Unit =
val items = List(Item("tea", 250), Item("cake", "320"))
val total = items.map(i => lineTotal(i)).sum
val byName = items.sorted
println(s"$total cents for ${byName.map(_.name).mkString(", ")}") from session import run
# The receipt as given, then the same file after its first mistake was fixed.
run("""
cd kata
!scala compile . --server=false
cd ../kata-after-first-fix
!scala compile . --server=false
""") Output
$ cd kata
$ scala compile . --server=false
-- [E007] Type Mismatch Error: Receipt.scala:8:50
8 | val items = List(Item("tea", 250), Item("cake", "320"))
| ^^^^^
| Found: ("320" : String)
| Required: Long
|
| longer explanation available when compiling with `-explain`
1 error found
Compilation failed
[exit status 1]
$ cd ../kata-after-first-fix
$ scala compile . --server=false
-- [E171] Type Error: Receipt.scala:9:38
9 | val total = items.map(i => lineTotal(i)).sum
| ^^^^^^^^^^^^
|missing argument for parameter quantity of method lineTotal: (item: Item, quantity: Int): Long
-- [E172] Type Error: Receipt.scala:10:27
10 | val byName = items.sorted
| ^
|No given instance of type Ordering[B] was found for parameter ord of method sorted in trait StrictOptimizedSeqOps.
|I found:
|
| scala.math.Ordering.ordered[B](
| /* missing */summon[scala.math.Ordering.AsComparable[B]])
|
|But no implicit values were found that match type scala.math.Ordering.AsComparable[B]
|
|where: B is a type variable with constraint >: Item
|.
|
|The following import might make progress towards fixing the problem:
|
| import scala.math.Ordered.orderingToOrdered
|
2 errors found
Compilation failed
[exit status 1]
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 kata_session.py
The mismatch on line 8 left the type of items in doubt, and the compiler does not report errors that may only
follow from an earlier one. Once "320" became 320, items was a list of Item, and both remaining errors appeared at once. Compile
after each fix: the messages change as the code does, and the newest ones are the ones that count.
Checkpoint
Check: Codes and the first error
Practise: repair the receipt
Copy kata/Receipt.scala into an empty folder and fix the three mistakes so that scala run . prints
1140 cents for cake, tea. Each item is bought twice, and the names come in alphabetical order. Fix the cause of each
error, not only its message: the result must be right as well as compile.
First hint: the last two errors are E171 and E172, the same codes as in the session above. lineTotal needs the
quantity, and sorted needs to know how to order items; sortBy(_.name) is one way to tell it.
Then check the five ideas of this lesson, from reading one message to fixing the first error first. A wrong answer says exactly what it misses:
Practice that adapts to you
Practise this lesson
14 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Fresher · What does -Werror do, and why do teams turn it on in CI?
-Werror makes the compiler treat every warning as an error: a build that would finish with warnings fails instead,
with the message No warnings can be incurred under -Werror. Teams turn it on in CI because some warnings predict real
bugs. A non-exhaustive match, warning E029, compiles, and the program then throws MatchError on the value the
warning named; with -Werror the same code cannot be merged. It also stops warnings from piling up until nobody reads
them. It works together with the flags that produce warnings, such as -deprecation, -feature and -Wunused:all.
The usual way to adopt it is to fix the existing warnings first, then switch it on in CI so the count stays at zero,
and to keep it off while experimenting locally if it gets in the way.
Key takeaways
- A diagnostic gives a code, the file, line and column, the line with a caret, and for a type error what was found against what was required; their difference is usually the fix.
- E171 means a missing argument and E172 a missing given instance; fix the cause, for example by giving a type an
Ordering, rather than trying the imports the message suggests. - A warning such as E029 lets the build pass, and the program can still crash on the value it named;
-Werrorturns warnings into errors. -deprecation,-featureand-Wunused:allshow what the compiler otherwise holds back or sums up in one line, and-explainadds its reasoning.- The Scala 3 Reference explains every code from E001 to E234; fix the first error first and compile again, because errors can hide the ones after them.
Terms in this lesson
- diagnostic
- A message from the compiler about the source: an error, which stops the build, or a warning, which does not. Scala 3 diagnostics carry a code such as E007.
- exhaustive match
- A match with a case for every possible value of its type. When the compiler finds a value that no case covers, it warns with E029, and that value throws MatchError at run time.
- given instance
- A value that the compiler passes by itself to a parameter declared with using, chosen by its type. sorted, for example, needs a given Ordering for the element type.
References
- Scala 3 Reference: compiler error codes (Scala Center and EPFL (docs.scala-lang.org))
- Scala 3 Reference: E007, Type Mismatch (Scala Center and EPFL (docs.scala-lang.org))
- Scala 3 Reference: E029, Pattern Match Exhaustivity (Scala Center and EPFL (docs.scala-lang.org))
- Scala 3 Reference: E172, Missing Implicit Argument (Scala Center and EPFL (docs.scala-lang.org))
- Scala 3 migration guide: new compiler options (Scala Center and EPFL (docs.scala-lang.org))
- Scala 3 migration guide: compiler options lookup table (Scala Center and EPFL (docs.scala-lang.org))
- Scala CLI compile command (compiler options, Bloop and --server=false) (VirtusLab (Scala CLI))
- Scala 3 Reference: enums (Scala Center and EPFL (docs.scala-lang.org))
Report a problem with this lesson
Kept only in this browser. Your Learn progress