Skip to content

Errors ​

Every error chamberu throws extends ChamberuError, which extends ebec's BaseError. Each carries a code; the codes are exported as ErrorCode.

ClassErrorCodeCodeThrown when
InvalidAgentDefinitionErrorINVALID_AGENT_DEFINITIONinvalid_agent_definitionAn agent name, trigger id or cron expression is invalid; duplicate agent names; an unknown notifier; an empty resumeSecret; dispatch() for an unknown agent
InvalidResumeTokenErrorINVALID_RESUME_TOKENinvalid_resume_tokenA resume token is malformed, forged, expired or belongs to another wait point
InvalidRunStateErrorINVALID_RUN_STATEinvalid_run_stateA run is not in the status an operation needs: resuming a run that is not waiting, cancelling a settled run, a store guard (expectStatus, expectOwner) that does not match
RunNotFoundErrorRUN_NOT_FOUNDrun_not_foundresume(), cancel() or updateRun() for an unknown run
BudgetExceededErrorBUDGET_EXCEEDEDBudgetExceededA run hit maxSteps or maxTokens while the model still wanted tools
TimeoutErrorTIMEOUTTimeoutAn execution exceeded timeoutMs
FatalToolErrorFATAL_TOOLFatalToolError (or a custom code)A tool decides the run must fail
LeaseLostErrorLEASE_LOSTlease_lostReported to onError when an engine stops executing a run whose claim it lost; carries runId
ValidationErrorVALIDATIONvalidation_errorA state document fails its schema; carries issues

Run errors ​

A failed run stores { code, message } in run.error. For budget, timeout and fatal tool failures the code is the error's code. Any other thrown value gets its own code if it has a string one, else Error.

ts
const run = await engine.getRun(runId);
if (run?.status === RunStatus.FAILED) {
    switch (run.error?.code) {
        case ErrorCode.BUDGET_EXCEEDED:
            return 'Raise maxSteps or maxTokens, or narrow the instructions.';
        case ErrorCode.TIMEOUT:
            return 'Raise timeoutMs or make the tools faster.';
        case ErrorCode.FATAL_TOOL:
            return `A tool stopped the run: ${run.error.message}`;
        default:
            return run.error?.message;
    }
}

Errors without a caller ​

Some errors happen where nobody awaits: a lost lease, a failed notification, a listener that throws, a failed recovery pass. They go to onError(error, run?), by default console.error. Pass your logger. A LeaseLostError there is informational: another replica carries the run on.

ts
const engine = new RunEngine({
    store,
    agents,
    resumeSecret,
    onError: (error, run) => {
        if (error instanceof LeaseLostError) {
            // another replica carries the run on; nothing to do
            return;
        }
        logger.error({ err: error, runId: run?.id }, 'chamberu');
    },
});