Oils Error Catalog, With Hints

This doc lists errors from Oils (both OSH and YSH), with hints to help you fix them.

Each error is associated with a code like OILS-ERR-42, a string that search engines should find.

Table of Contents
How to Contribute
To Preview this Doc
Parse Errors - Rejected Input
OILS-ERR-10
OILS-ERR-11
OILS-ERR-12
OILS-ERR-13
OILS-ERR-14
OILS-ERR-15
OILS-ERR-16
OILS-ERR-17
Runtime Errors - Traditional Shell
OILS-ERR-100
OILS-ERR-101
OILS-ERR-102
Runtime Errors - Oils and YSH
OILS-ERR-200
OILS-ERR-201
OILS-ERR-202
OILS-ERR-203
OILS-ERR-204
Runtime Errors: strict:all
OILS-ERR-300
OILS-ERR-301
OILS-ERR-302
Appendix
Kinds of Errors from Oils
Contributors

How to Contribute

If you see an error that you don't understand:

  1. Ask a question on #oil-help on Zulip. What's the problem, and what's the solution?
  2. Then grep the source code for the confusing error message. Tag it with a string like OILS-ERR-43, picking a new number according to the conventions below.
  3. Add a tagged section below, with hints and explanations.
  4. Optionally, add your name to the acknowledgements list at the end of this doc.

Note that error messages are hard to write, because a single error could result from many different user intentions!

To Preview this Doc

Right now I use this command:

build/doc.sh split-and-render doc/error-catalog.md

Then paste this into your browser:

file:///home/andy/git/oilshell/oil/_release/VERSION/doc/error-catalog.html

(Replace with your home dir)

Parse Errors - Rejected Input

Roughly speaking, a parse error means that text input was rejected, so the shell didn't try to do anything.

Examples:

echo )   # Shell syntax error

type -z  # -z flag not accepted

These error codes start at 10.

OILS-ERR-10

      setvar x = true
             ^
[ -c flag ]:3: setvar couldn't find matching 'var x' (OILS-ERR-10)

Related help topics:

OILS-ERR-11

  echo $'\z'
         ^
[ -c flag ]:1: Invalid char escape in C-style string literal (OILS-ERR-11)

Related help topics:

OILS-ERR-12

  echo "\z"
        ^
[ -c flag ]:1: Invalid char escape in double quoted string (OILS-ERR-12)

Related help topics:

OILS-ERR-13

  echo \z
       ^~
[ -c flag ]:1: Invalid char escape in unquoted word (OILS-ERR-13)

OILS-ERR-14

  if ((1 > 0 && 43 > 42)); then echo yes; fi
     ^~
[ -c flag ]:1: Bash (( not allowed in YSH (parse_dparen, see OILS-ERR-14 for wart)

Two likely causes:

Examples:

if (1 > 0 and 43 > 42) {  # YSH-style
  echo yes
}

if ( (x + 1) < n) {  # space between ( ( avoids ((
  echo yes
}

OILS-ERR-15

      if (a || b && c) {
            ^~
[ -c flag ]:2: Use 'or' in expression mode (OILS-ERR-15)

Expression mode uses not or and, rather than ! || &&. See Command vs. Expression Mode for details.

No:

if (!a || b && c) {
  echo no
}

Yes:

if (not a or b and c) {
  echo yes
}

Command mode is the opposite; it uses ! || &&, rather than not or and:

No:

# Command mode
if not test --dir a or test --dir b and test --dir c {
  echo no
}

Yes:

# Command mode
if ! test --dir a || test --dir b && test --dir c {
  echo yes
}

OILS-ERR-16

  for x in (1 .. 5) {
              ^~
[ -c flag ]:1: Use ..< for half-open range, or ..= for closed range (OILS-ERR-16)

There are two ways to construct a Range. The ..< operator is for half-open ranges and the ..= operator is for closed ranges:

for i in (0 ..< 3) {
  echo $i
}
=> 0
=> 1
=> 2

for i in (0 ..= 3) {
  echo $i
}
=> 0
=> 1
=> 2
=> 3

OILS-ERR-17

  echo --flag=u'foo'
               ^
[ -c flag ]:1: Invalid quoted word part in YSH (OILS-ERR-17)

In YSH, --flag='foo' is allowed, but --flag=u'foo\n' is not. In the latter case, it's not clear if the u is literal.

Try one of these alternatives:

ysh$ echo u'--flag=foo\n'        # quote the whole thing

ysh$ echo --flag u'foo\n'        # space instead of =

ysh$ echo --flag=$myvar          # assign to variable first

ysh$ echo $['--flag=' ++ myvar]  # expression sub

Runtime Errors - Traditional Shell

These errors may occur in shells like bash and zsh.

They're numbered starting from 100. (If we have more than 90 parse errors, we can start a new section, like 300.)

OILS-ERR-100

  findz
  ^~~~~
[ -c flag ]:1: Command 'findz' not found (OILS-ERR-100)

The shell tried to execute an external command, but couldn't.

OILS-ERR-101

Let's look at three instances of this error.

  declare -A assoc; assoc[x]=1
                    ^~~~~~
[ -c flag ]:1: fatal: Assoc array keys must be strings: $x 'x' "$x" etc. (OILS-ERR-101)

Same idea here:

  declare -A assoc; echo ${assoc[x]}
                                 ^
[ -c flag ]:1: fatal: Assoc array keys must be strings: $x 'x' "$x" etc. (OILS-ERR-101)

The third example is tricky because unset takes a string. There's an extra level of parsing, which:

  assoc[k]
       ^
[ dynamic LHS word at line 1 of [ -c flag ] ]:1

  declare -A assoc; key=k; unset "assoc[$key]"
                                 ^
[ -c flag ]:1: fatal: Assoc array keys must be strings: $x 'x' "$x" etc. (OILS-ERR-101)

To fix it, consider using single quotes:

unset 'assoc[$key]'

OILS-ERR-102

  var cmd = ^(seq 3)
              ^~~
[ stdin ]:1: Command 'seq' not found in pure mode (OILS-ERR-102)

The shell tried to execute a command in pure mode, but couldn't.

In pure mode, only user-defined procs and a few builtin commands can be the "first word".

Runtime Errors - Oils and YSH

These errors don't occur in shells like bash and zsh.

They may involve Python-like expressions and typed data.

They're numbered starting from 200.

OILS-ERR-200

  cat ("myfile")
      ^
[ -c flag ]:1: fatal: 'cat' appears to be external. External commands don't accept typed args (OILS-ERR-200)

OILS-ERR-201

  = "age: " + "100"
            ^
[ -c flag ]:1: fatal: Binary operator expected numbers, got Str and Str (OILS-ERR-201)

  = 100 + myvar
        ^
[ -c flag ]:2: fatal: Binary operator expected numbers, got Int and Str (OILS-ERR-201)

OILS-ERR-202

  pp (42.0 === x)
                ^~~
[ -c flag ]:3: fatal: Equality isn't defined on Float values (OILS-ERR-202)

Floating point numbers shouldn't be tested for equality. Alternatives:

= abs(42.0 - x) < 0.1
= floatEquals(42.0, x) 

OILS-ERR-203

  var mylist = [1,2,3]; write $[mylist]
                              ^~
[ -c flag ]:1: fatal: Expr sub got a List, which can't be stringified (OILS-ERR-203)

Or:

OILS-ERR-204

  x=$(date)
    ^~
impure.sh:1: fatal: Command subs aren't allowed in pure mode (OILS-ERR-204)

In pure mode, the shell can't do I/O. It's intended for config file evaluation and pure functions.

Runtime Errors: strict:all

OILS-ERR-300

  if ! ls | wc -l; then echo failed; fi
          ^
[ -c flag ]:1: fatal: Command conditionals should only have one status, not Pipeline (strict_errexit, OILS-ERR-300)

Compound commands can't be used as conditionals because it's ambiguous.

It confuses true/false with pass/fail. What if part of the pipeline fails? What if ls doesn't exist?

This YSH idiom is more explicit:

try {
  ls | wc -l
}
if failed {
  echo failed
}

OILS-ERR-301

    if shell-func; then
       ^~~~~~~~~~
foo.sh:9: fatal: Can't run functions or procs while errexit is disabled (OILS-ERR-301)

This error prevents you from hitting a pitfall with set -e aka errexit, as it's defined in POSIX shell.

Here are some shell-compatible solutions:

In YSH, use the try builtin instead of if.

OILS-ERR-302

  FOO=bar eval 'echo FOO=$FOO'
  ^~~~
[ stdin ]:3: fatal: Special builtins can't have prefix bindings (OILS-ERR-302)

In POSIX shell, prefix bindings have two behaviors:

  1. Usually, they set the environment temporarily.
  2. When applied to "special builtins", the bindings persist, and are not exported.

This is invisible and confusing, so YSH has shopt --set strict_env_binding to make the first meaning the only one.

Try this instead:

var FOO = 'bar'
eval 'echo FOO=$FOO'

Appendix

Kinds of Errors from Oils

Contributors

(If you updated this doc, feel free to add your name to the end of this list.)

Generated on Wed, 25 Jun 2025 16:06:10 +0000