veR2

Errors

Every error veR2 throws on purpose is a Ver2Error subclass with a stable code. Switch on code, not on class names or messages:

import { Ver2Error } from "@ver2/sdk";
 
try {
  await ver2.put(key, bytes);
} catch (e) {
  if (!(e instanceof Ver2Error)) throw e;
  switch (e.code) {
    case "CONCURRENCY_CONFLICT":
      // another writer got there first: re-read and retry
      break;
    case "OPERATION_INCOMPLETE":
      // run recovery (ver2 reconcile, or ver2.recover(key))
      break;
    default:
      throw e;
  }
}

e.details carries structured context where it applies: key, versionId, reason, opId, or status and retryable for storage errors. Messages never include credentials.

Error codes

CodeMeaningWhat to do
INVALID_KEYThe key failed validation: a . or .. segment, a control character, a lone surrogate, a key inside the reserved namespace, or a key too long for R2Fix the key. veR2 checks keys before any I/O because R2 resolves dot segments, so an unchecked key could write somewhere else
OBJECT_NOT_FOUNDThere is no current object for the key (never written, or deleted)Check the key, or download a specific version from the history
VERSION_NOT_FOUNDNo restorable version with that ID exists for the key (unknown ID, or a delete marker)List the versions and pick a put version
CONCURRENCY_CONFLICTAnother writer changed the key during the operationRetry. veR2 serializes writers to one key; the loser gets this error
INTEGRITY_CHECK_FAILEDDownloaded bytes don't match the SHA-256 recorded for that version, or the version object was replacedDon't use the data. The stream errors at the end, so treat partial output as untrusted
OPERATION_INCOMPLETEAn operation was interrupted and veR2 couldn't prove from storage whether it finishedRun ver2 reconcile (or ver2.recover(key)). If it reports stuck, inspect the key and use --accept-live to keep what's there now
CONFIGURATION_ERRORInvalid options: a bad namespace, missing bucket or endpoint, a non-R2 endpoint, or missing CLI environment variablesFix the configuration; the message lists what's wrong
MANIFEST_INVALIDThe key's manifest is unreadable or has an unsupported schemaThe version objects are intact, but the manifest must be repaired or removed by hand for now. Automated rebuild from version objects is planned
STORAGE_ERRORAn R2 request failedCheck retryable: it is true for rate limiting (429), network errors and 5xx responses, so back off and retry; otherwise inspect status and the message

Storage errors and retries

R2 allows roughly one write per second to the same key. Rapid rewrites of a hot key return 429s, which surface as STORAGE_ERROR with retryable: true. veR2's S3 driver already retries each request (3 attempts by default, see Configuration); a retryable error reaching your code means those attempts ran out.

In the CLI

The CLI maps error codes to exit codes: INVALID_KEY and CONFIGURATION_ERROR exit 2, CONCURRENCY_CONFLICT exits 3, OPERATION_INCOMPLETE exits 4, INTEGRITY_CHECK_FAILED exits 5, and everything else exits 1. With --json, the code is in error.code on stderr.