Errors
Every method on api that reaches Voshi throws when something goes wrong. It never returns an error object, a null, or a status code — so a call that returns has succeeded, and try/catch is the whole of error handling.
try {
await this.api.storage.location.set(setup)
} catch (err) {
if (err.name === 'VoshiPermissionError') {
this.setStatus('Only the instructor can change the setup.')
} else if (err.name === 'VoshiAuthenticationError') {
this.setStatus('Your session has ended. Open the activity again from your course.')
} else {
console.error(err)
this.setStatus('Something went wrong saving your work. Please try again.')
}
}
Every error's name is its class name, so err.name === 'VoshiPermissionError' is the test. The classes themselves live in the Voshi API module that Voshi loads, not in a file of yours, so there is nothing to import.
The kinds
All of them extend VoshiApiError, which carries message, status (the HTTP status, when there was a response), method and url (which request), and details (whatever the server said).
| Error | Status | Meaning | What to say |
|---|---|---|---|
VoshiNetworkError | none | The request never got an answer: offline, or the request was aborted. | "Check your connection and try again." |
VoshiAuthenticationError | 401 | The launch session has ended. Sessions last a long time, but not forever. | "Open the activity again from your course." |
VoshiPermissionError | 403 | This role may not do that — a student writing course or location, say. | Hide the feature behind api.isStaff in the first place. |
VoshiNotFoundError | 404 | No such file, location, or object. From files.info() or files.get() on a key that holds nothing. | Treat as "not there yet." |
VoshiValidationError | 400 / 422 | The request was not acceptable: a non-object to set(), a bad file key, a score outside 0 to 1, a storage object over its size limit. Often thrown before anything is sent. | A bug in the tool; err.message says which argument. |
VoshiServerError | 5xx | Voshi failed. | "Please try again in a moment." Retrying is reasonable. |
VoshiGradeUnavailableError | none | submitGrade() with canSubmitGrade false. | Don't call it; check first. |
VoshiGradeRejectedError | 200 | Voshi recorded the attempt, but the LMS refused the score. err.passback.data.error has the reason. | "Your score could not be reported," with err.message. The attempt is visible in the Grades tab. |
Two rules
Log the detail, show the learner a sentence. console.error(err) keeps the status, URL, and server message for whoever is debugging. The learner gets plain language, and never a raw error string.
Never claim success before the call resolves. "Saving…" until the await returns, then "Saved" — or the catch block's message. This matters most for grades, where a learner who sees "reported" and closes the tab will not try again.