Skip to content

Error handling

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

The three execution modes

Every builder’s .execute() method supports three modes that control how per-record errors are surfaced:

ModeJavaPythonBehaviorBest for
Defaultexecute()await … .execute()Single-key: throws immediately. Batch: errors embedded in streamSimple cases
In-stream errorsexecute(ErrorStrategy.IN_STREAM)await … .execute(on_error=ErrorStrategy.IN_STREAM)All errors embedded as RecordResult entries in the streamUniform handling of single + batch
Error callbackexecute(errorHandler)await … .execute(on_error=<callable>)Errors dispatched to callback, excluded from streamLogging, fire-and-forget

Java exposes the same three modes through overloads of execute() and executeAsync(). The Python SDK uses await … .execute(on_error=…) as the entry point for the async surface (aerospike_sdk.aio.*); the synchronous surface (aerospike_sdk.sync.*) offers the same builders with blocking .execute(on_error=…) calls. Either way there is no separate executeAsync() — choosing async vs sync is a matter of which session/client class you import.

Mode 1: Default (execute())

Single-key operations throw on failure:

try {
session.update(users.id("no-such-key"))
.bin("name").setTo("Alice")
.execute();
} catch (AerospikeException e) {
System.out.println("Failed: " + e.getResultCode()); // 2 = KEY_NOT_FOUND_ERROR
}

📖 API reference: DataSet.id(...) | Session.update(DataSet) | ChainableOperationBuilder.bin(...) | ChainableQueryBuilder.bin(...) | ChainableQueryBuilder.execute() | AerospikeException

Batch operations embed errors in the stream:

RecordStream stream = session
.update(users.id("exists"))
.bin("count").add(1)
.update(users.id("no-such-key"))
.bin("count").add(1)
.execute();
stream.forEach(result -> {
if (result.isOk()) {
System.out.println(result.getKey().userKey + ": success");
} else {
System.out.println(result.getKey().userKey + ": " + result.getMessage());
}
});

📖 API reference: DataSet.id(...) | ChainableQueryBuilder.bin(...) | BinBuilder.add(...) | ChainableQueryBuilder.execute() | RecordStream.forEach(...) | RecordResult.isOk()

Mode 2: ErrorStrategy.IN_STREAM

Forces all errors (including single-key) into the stream. Useful when you want uniform handling regardless of key count:

RecordStream stream = session.update(users.id("no-such-key"))
.bin("name").setTo("Alice")
.execute(ErrorStrategy.IN_STREAM);
stream.forEach(result -> {
if (!result.isOk()) {
System.out.println("Error: " + result.getResultCode() + " - " + result.getMessage());
}
});

📖 API reference: DataSet.id(...) | Session.update(DataSet) | ChainableOperationBuilder.bin(...) | ChainableQueryBuilder.bin(...) | ChainableQueryBuilder.execute() | RecordStream.forEach(...) | RecordResult.isOk() | ErrorStrategy | ErrorStrategy.IN_STREAM

Mode 3: ErrorHandler callback

Errors are dispatched to the handler and excluded from the stream. The stream contains only successful results:

RecordStream stream = session
.upsert(users.id("u1")).bin("name").setTo("Alice")
.upsert(users.id("u2")).bin("name").setTo("Bob")
.execute((key, index, exception) ->
System.err.println("Failed key " + key.userKey +
" at index " + index + ": " + exception.getMessage())
);
// stream contains only successful results
stream.forEach(result -> {
System.out.println(result.getKey().userKey + ": OK");
});

📖 API reference: DataSet.id(...) | ChainableQueryBuilder.bin(...) | ChainableQueryBuilder.execute() | RecordStream.forEach(...)

Inspecting RecordResult

Every result in the stream is a RecordResult. Key members:

JavaPythonReturnsThrows?
isOk()is_ok (attribute)true if result_code == OKNo
getResultCode()result_code (attribute)Integer result codeNo
getMessage()server_message (attribute; set when the Behavior’s error_detail_verbosity is MESSAGE)Human-readable error message (or null/None)No
toException()to_exception()The failure as an exception without throwing it. Check isOk() first in Java: on an OK row Java returns an exception carrying code 0, while Python returns NoneNo
orThrow()or_raise()self if OK, throws otherwiseYes
recordOrThrow()record_or_raise()The Record if OK, throws otherwiseYes
getRecord()record (attribute, may be None)The Record or null/None — does not throwNo
asBoolean()as_bool()true if OK, false if KEY_NOT_FOUND, throws otherwiseConditionally
getKey()key (attribute; user value in key.value)The Key for this operationNo
getIndex()index (attribute)Position in the batch (0-based)No
isInDoubt()in_doubt (attribute)Whether the write may have succeeded on the serverNo
getException()exception (attribute)The AerospikeException / AerospikeError the client attached, or null/None (server-reported row failures carry only a result code; use toException() / to_exception())No

Using failures() to isolate errors

RecordStream.failures() consumes the entire source stream and returns only the failed results. In Java this is a new RecordStream; in Python it is an awaitable that resolves to list[RecordResult].

RecordStream stream = session
.update(users.id("u1")).bin("count").add(1)
.update(users.id("u2")).bin("count").add(1)
.update(users.id("missing")).bin("count").add(1)
.execute(ErrorStrategy.IN_STREAM);
RecordStream errors = stream.failures();
errors.forEach(failure ->
System.err.println("Failed: " + failure.getKey().userKey + " → " + failure.getMessage())
);

📖 API reference: DataSet.id(...) | ChainableQueryBuilder.bin(...) | BinBuilder.add(...) | ChainableQueryBuilder.execute() | RecordStream.forEach(...) | ErrorStrategy | ErrorStrategy.IN_STREAM

Existence checks

The asBoolean() / as_bool() method translates as follows:

  • OK → true
  • KEY_NOT_FOUND → false
  • any other error → throws:
boolean exists = session.exists(users.id("user-1"))
.execute()
.getFirstBoolean()
.orElse(false);

📖 API reference: DataSet.id(...) | Session.exists(Key) | ChainableQueryBuilder.execute()

Decision guide

ScenarioRecommended mode
Simple single-key read/writeexecute() + try/catch
Batch where all failures are fatalexecute() + iterate and check isOk() / is_ok
Batch where you need consistent handlingexecute(ErrorStrategy.IN_STREAM) (Java) / execute(on_error=ErrorStrategy.IN_STREAM) (Python)
Batch where failures should be logged but not blockexecute(errorHandler) (Java) / execute(on_error=<callable>) (Python)
Need to collect all failures for retryIN_STREAM mode + .failures()

Malformed AEL text

AEL strings must conform to the AEL reference grammar, but neither SDK parses or validates AEL text locally. .where(...), selectFrom(...) / select_from(...), and the write-side *From(...) builders send the AEL string to the server as-is; the server parses and compiles it as part of each request. There is no local syntax check before sending, and no dedicated exception type for an AEL syntax error — a malformed expression comes back as an ordinary AerospikeException (Java) / AerospikeError (Python) from that request, typically carrying ResultCode.PARAMETER_ERROR.

try {
// Single-quoted strings and '==' are required; '=' is a parse error
session.query(users).where("$.name = 'Alice'").execute();
} catch (AerospikeException e) {
if (e.getResultCode() == ResultCode.PARAMETER_ERROR) {
// Malformed AEL syntax, or another rejected argument
}
}

📖 API reference: AerospikeException | AerospikeException.getResultCode() | ResultCode | Cluster.supportsAel()

PARAMETER_ERROR covers any rejected argument, not only AEL syntax, and the server does not always send a specific reason unless asked. Set errorDetailVerbosity / error_detail_verbosity to MESSAGE on the session’s Behavior to have the server’s explanation returned with the error. For parse coordinates, build traces, and filter-decision explainers specific to AEL text, see Debug AEL expressions. To catch AEL mistakes before they reach production, test the expression against Aerospike Voyager or a live server — there is no local syntax check to catch them earlier.

On a cluster that doesn’t support server-side AEL compilation, a string .where() call raises the same exception type instead, carrying ResultCode.OP_NOT_APPLICABLE — check Cluster.supportsAel() (Java) / cluster.supports_ael() (Python) up front, or fall back to the programmatic expression builder, to avoid depending on string AEL there.

Next steps

Query records

Build queries and AEL filters that pair with these execution modes.

Query records →