os/error
The last error from a file or process operation: its code, its message and the path that failed.
import os.error
When an operation in the fs.file, fs.dir, os.process or os.temp packages fails, it records a short report here: a code, a message, the operation and the path. Call Clear, run the operation, then ask HasError and Last. It is a single global record, like C's errno, not a returned value.
The plain functions of the os package do not record anything here; they only return -1. This package is a different thing from the general-purpose error package, which builds error values to return from your own functions; prefer that for new code that is not about files or processes.
Know what the standard packages actually record before you branch on it:
| Code | Recorded by |
|---|---|
IOError | Almost every failure: fs.dir (Mkdir, MkdirAll, Remove, RemoveAll, Copy, Move), fs.file (AtomicWrite, Copy, Move) and os.temp |
FileNotFound | Only fs.file.Delete, for any failure to delete, a missing permission included |
ProcessFailed | os.process, when a program cannot be started |
| the others | Nothing in the standard library yet; they are there for your own Set calls |
Reads and plain writes such as fs.file.ReadText and WriteText record nothing; check their results instead. The messages are fixed English phrases such as delete failed, not the system's reason, and system_code is filled in only by os.process.
Check an operation and explain the failure
The usual pattern has three steps: call Clear, run the operation, then ask HasError. Last returns an OSError with the code to branch on, the path that failed and the name of the operation, which is enough to turn the failure into a message a person understands.
import os.error
import fs.file
func explain(e: error.OSError): str:
switch e.code:
error.FileNotFound: ret "there is no such file: " + e.path end
error.IOError: ret e.operation + " failed on " + e.path end
error.ProcessFailed: ret "could not start " + e.path end
end
ret "something else went wrong in " + e.operation
end
func remove_draft(name: str):
error.Clear()
file.Delete(name)
if error.HasError():
println "could not delete:", explain(error.Last())
ret
end
println "deleted", name
end
func main:
file.WriteText("draft.txt", "notes")
remove_draft("draft.txt")
remove_draft("draft.txt")
endCompare code with the constants of this package, never message: the message is meant for people and may change between releases.
Errors stay until you clear them
A failed call records an error, but a successful call does not remove it. So HasError after a good call can still be true because of something that failed much earlier. Call Clear just before the operation you want to check.
import os.error
import fs.file
func main:
file.Delete("missing.txt")
file.WriteText("ok.txt", "fine")
println "after a good write:", error.HasError(), error.LastMessage()
error.Clear()
file.WriteText("ok.txt", "still fine")
println "after Clear and a good write:", error.HasError()
file.Delete("ok.txt")
println "after deleting ok.txt:", error.HasError()
endThe record is a single global value for the whole program, so it is not a safe channel between threads: a failure in one thread can overwrite another thread's error before it is read. Check the error in the same thread, right after the call.
Report errors from your own functions
Set records an error the same way the standard packages do. A helper that reads files can use it, and its callers then check it with the same HasError and Last they use everywhere else. Pass the name of your function as the operation and the file as the path, so the message says where things went wrong.
import os.error
import fs.file
func load_port(path: str): int:
error.Clear()
if not file.Exists(path):
error.Set(error.FileNotFound, "config file is missing", "load_port", path, 0)
ret 0
end
text := file.ReadText(path).trim()
port := text.to_int()
if port <= 0 or port > 65535:
error.Set(error.InvalidPath, "not a port number: " + text, "load_port", path, 0)
ret 0
end
ret port
end
func show(path: str):
port := load_port(path)
if error.HasError():
e := error.Last()
println e.operation + "(" + e.path + "):", e.message
ret
end
println path, "says port", port
end
func main:
file.WriteText("good.conf", "8080\n")
file.WriteText("bad.conf", "eighty\n")
show("good.conf")
show("bad.conf")
show("none.conf")
file.Delete("good.conf")
file.Delete("bad.conf")
endA program that will not start
The os.process package records ProcessFailed here when it cannot start a program at all, for example when the path is wrong. That is different from a program that starts and then exits with a non-zero code: then there is no error here, and you read the code from Wait.
import os.error
import os.process
func main:
mut args := Vector {} as Vector<str>
defer args.free()
args.push("--version")
error.Clear()
mut p := process.StartCaptured("/no/such/program", args)
if error.HasError():
e := error.Last()
println "could not start:", e.code == error.ProcessFailed, e.operation, e.path
ret 0
end
code := process.Wait(p)
process.Cleanup(p)
println "started, but it exited with", code
endThe system_code field holds the operating system's own number when the package knows it: the posix_spawnp result on Unix and GetLastError on Windows, from os.process only. Everywhere else it is zero. It is useful in logs; branch on code.
Types
OSError
struct OSError| Name | Type | Description |
|---|---|---|
code | int = 0 | The error code; one of the constants above. |
message | str = "" | A short fixed English phrase such as mkdir failed; it does not carry the system's reason. |
operation | str = "" | The name of the function that failed. |
path | str = "" | The path that had the problem. |
system_code | int = 0 | The operating system's own error number when known; only os.process fills it in, everywhere else it is 0. |
import os.error
import fs.file
func main:
error.Clear()
println error.HasError()
file.Delete("a file that does not exist.txt")
if error.HasError():
e := error.Last()
println e.code == error.FileNotFound, e.operation, e.message
println error.LastCode(), error.LastMessage()
end
error.Set(error.Timeout, "time ran out", "waiting", "", 0)
println error.LastCode() == error.Timeout, error.LastMessage()
println error.None, error.PermissionDenied, error.AlreadyExists, error.InvalidPath, error.NotSupported, error.IOError, error.ProcessFailed
endConstants and variables
None
const None: i32 = 0The example for this item is shown with the ones above: os-error-Last.salam
FileNotFound
const FileNotFound: i32 = 1fs.file.Delete records it, for any failed delete.The example for this item is shown with the ones above: os-error-Last.salam
PermissionDenied
const PermissionDenied: i32 = 2IOError.The example for this item is shown with the ones above: os-error-Last.salam
AlreadyExists
const AlreadyExists: i32 = 3Set calls.The example for this item is shown with the ones above: os-error-Last.salam
InvalidPath
const InvalidPath: i32 = 4Set calls.The example for this item is shown with the ones above: os-error-Last.salam
NotSupported
const NotSupported: i32 = 5The example for this item is shown with the ones above: os-error-Last.salam
IOError
const IOError: i32 = 6fs.dir, fs.file and os.temp record.The example for this item is shown with the ones above: os-error-Last.salam
Timeout
const Timeout: i32 = 7The example for this item is shown with the ones above: os-error-Last.salam
ProcessFailed
const ProcessFailed: i32 = 8The example for this item is shown with the ones above: os-error-Last.salam
Functions
Set
func Set(code: int, message: str, operation: str, path: str, system_code: int)The example for this item is shown with the ones above: os-error-Last.salam
Clear
func Clear()The example for this item is shown with the ones above: os-error-Last.salam
Last
func Last(): OSErrorThe example for this item is shown with the ones above: os-error-Last.salam
LastCode
func LastCode(): intThe example for this item is shown with the ones above: os-error-Last.salam
LastMessage
func LastMessage(): strThe example for this item is shown with the ones above: os-error-Last.salam
HasError
func HasError(): boolClear.The example for this item is shown with the ones above: os-error-Last.salam