lippy.

Understanding lippy's errors

Good error messages are the point of lippy, not an afterthought. When something's wrong, an error tells you what happened, where, and usually what you probably meant — in plain words, never jargon. This page shows how to read them.

The shape of an error

Every error starts by saying which of two things happened:

Then it shows the line, points a caret at the exact spot, explains in a sentence or two, and — when it's confident — offers a hint:

lippy stopped at line 2 of greet.lip

  line 2:  greeting is "hello, " + name
                                 ^
  + only works on numbers, but the left side is the string "hello, ".
  To build strings, put the value inside the quotes.

  hint: greeting is "hello, {name}"

A hint only appears when lippy is sure of the correction — a wrong hint is worse than none, so when it isn't confident it stays quiet.

Common mistakes, and what to write instead

Coming from another language, these are the ones you'll meet first — and lippy always suggests the fix:

You wrote lippy suggests
= or == to compare equals to compare, is to assign
is inside a condition drop it — comparisons work on their own
!=, <, >, <=, >= not equals, less than, greater than, at most, at least
&&, ||, ! and, or, not
+ with a string interpolation: "hello, {name}"
a call inside a paren-free call parenthesise the inner one: split trim(line)
elif / elsif else if
while loop with stop when
a misspelled name or keyword did-you-mean the closest real one

A few real ones

A keyword typo, caught before anything runs:

lippy couldn't read greet.lip

  line 1:  fnu greet(who)
           ^^^
  lippy doesn't know the word "fnu".

  hint: did you mean fun?

The = habit, in a condition:

lippy couldn't read check.lip

  line 1:  if guess = secret then
                    ^
  lippy doesn't use =. To compare two things, use equals.
  To put a value in a name, use is.

  hint: if guess equals secret then

The one trap that paren-free calls create — everything after a name belongs to it:

lippy stopped at line 1 of count.lip

  line 1:  total is len args + 1
                        ^^^^^^^^
  without parentheses, everything after len belongs to it — so this
  asks for len(args + 1), and + only works on numbers, but args is a list.

  hint: total is len(args) + 1

A misspelled name, with the fix:

lippy stopped at line 2 of tally.lip

  line 2:  say cuont
               ^^^^^
  there's nothing called "cuont" here.

  hint: did you mean count?

When a script stops partway

A runtime error shows the story — the line that failed, then the trail of calls that led there, written as sentences rather than a raw trace:

lippy stopped at line 3 of deploy.lip

  line 3:  run "rsync -a {src}/ {dst}/"
           ^^^
  rsync finished with exit code 23 (partial transfer).

  while running backup, called from line 12
  while running main script

  hint: to carry on when a command fails, use attempt instead of run

That last hint points at attempt — the way to let something fail without stopping the whole script, turning the failure into a result you can check.