Skip to content

When things go wrong

Things fail. A file isn’t where you expected, a web service is down, you divide by zero. This chapter shows what MaSH does and how to take control.

MaSH doesn’t stop when a line fails. It notes the error and carries on with the next line:

printline "start"
set result to 10 / 0
printline "still running"
start
still running

In the editor, the failed lines are listed under Unhandled errors below the output. In Settings > MaSH > Logs, the run shows the same list. A script that “worked” but has unhandled errors in its log probably didn’t do what you meant.

Put an error block straight after the line that might fail. If that line fails, the block runs:

printline "start"
set result to 10 / 0
error
printline "Error on line {{mash.error.line}}: {{mash.error.message}}"
exit
end
printline "not reached"
start
Error on line 2: Division by zero

Inside the block, mash.error describes what went wrong:

PropertyWhat it holds
mash.error.messagewhat went wrong, in words
mash.error.linethe line number in your script
mash.error.expressionthe line of script that failed

exit stops the script and counts it as a success. Leave exit out, and the script carries on after the error block.

throw "message" records an error of your own and stops the block it is in. The script that called that block then skips ahead to its next error block. An error block catches a throw from a block it called, not from a line above it in the same block. If nothing catches it, the run ends and the message is the run’s error.

block checkAge age
if age is less than 0
throw "Age cannot be negative"
end
printline "age is fine"
end
checkAge(-5)
printline "not reached"
error
printline "Caught: {{mash.error.message}}"
end
Caught: Age cannot be negative

Rather than an error block after every line, name a block as the script’s error handler by setting errorblock:

set errorblock to "onError"
block onError
printline "Oops: {{mash.error.message}} (line {{mash.error.line}})"
end
set a to 1 / 0
printline "carried on"
Oops: Division by zero (line 7)
carried on

The production scripts our customers run start with a handler like this one, and use it to print a line for the log.

Three ways to stop, each meaning something different to whoever reads the log:

  • return ends the script quietly. Use it when there’s simply nothing to do.
  • exit ends the script and records a success.
  • fail "message" ends the script and records a failure, with your message.
printline "checking"
set found to false
if not found
printline "nothing to do"
return
end
printline "never reached"
checking
nothing to do

fail is the one to use when something is wrong and a person should hear about it. It shows in Logs as a failed run:

set share to mash.config.get("DEST_SHARE")
if not share
fail "DEST_SHARE is not set on this automation."
end

ensure is a tidy way to say “this must be true, or stop”. If the condition is false, the else part runs:

set count to 0
ensure count is more than 0 else
printline "Nothing to process"
return
end
printline "Processing..."
Nothing to process

The else part has to leave the script or the loop: it ends with return, next, break, fail or exit. MaSH refuses to run a script where it doesn’t.

Most real errors come from a value that isn’t there. Combine ?? with a check:

set person to {name: "Ada"}
set phone to person["phone"] ?? ""
if mash.str(phone).length() is 0
printline "No phone number"
end
No phone number

Add an errorblock to one of your earlier scripts. Then cause an error on purpose, such as dividing by zero, and check that your handler runs.

Next, you’ll leave the sandbox of numbers and text and start working with real files.