WebAssembly / wasi-io

I/O Types proposal for WASI
Other
143 stars 19 forks source link

How should read/write errors be represented? #47

Closed alexcrichton closed 1 year ago

alexcrichton commented 1 year ago

As of https://github.com/bytecodealliance/wasmtime/pull/7090 the representation of input/output stream error types will be:

    /// An error for stream operations.
    enum stream-error {
        /// The last operation (a write or flush) failed before completion.
        last-operation-failed,
        /// The stream is closed: no more input will be accepted by the
        /// stream. A closed output-stream will return this error on all
        /// future operations.
        closed
    }

My intention as part of https://github.com/bytecodealliance/wasmtime/issues/7017, however, is to change this to:

variant stream-error {
    last-operation-failed(error),
    closed,
}

resource error {
    ??
}

Notably the last-operation-failed will have a means of communicating what the actual underlying failure was. This enables guests to learn details about why the operation failed and handle them as necesesary. Specific errors will be "downcasted" with accessors such as:

package wasi:filesystem;

interface types {
    use wasi:io/streams.{error}

    get-error-code: func(err: borrow<error>) -> option<errno>

    enum errno {
        // ...
    }
}

Where each individual source of {input,output}-stream would provide an accessor that when given wasi:io/streams.{error} would optionally return typed information about the error. This is intended for whenever a specific class of error needs to be handled in a particular way and affords for how wasi:io/streams doesn't want to exhaustively list all of the kinds of errors that downstream users can use.

When working generically with errors, however, I at least think it can still be useful to be able to get information about errors at least for the purposes of displaying to humans to help diagnose issues. To that end there's a design question for whether wasi:io/streams.{error} should have any methods on it. Personally I would propose:

resource error {
    to-debug-string: func() -> string
}

This would mean that all errors, regardless of where they come from, can at least be stringified for debugging if necessary. This is somewhat risky, however, since error messages can vary across embeddings (e.g. Unix vs Windows, locales, etc). This is consequently a portability hazard if users rely on specific string structure. Furthermore it's sometimes possible to parse out information from the debug string that isn't otherwise available via accessors like get-error-code.

@sunfishcode, @lukewagner, @pchickey, and I talked about this a day or so ago and I wanted to write up the current state of things. Additionally if others have feedback it'd be good to hear here!

sunfishcode commented 1 year ago

https://github.com/WebAssembly/wasi-io/pull/52 added an error resource with a to-debug-string method, which is what the issue here proposed.