Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions client/src/com/aerospike/client/AerospikeException.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class AerospikeException extends RuntimeException {
protected transient Policy policy;
protected List<AerospikeException> subExceptions;
protected int resultCode = ResultCode.CLIENT_ERROR;
protected int subcode = SubCode.NONE;
protected int iteration = -1;
protected boolean inDoubt;

Expand All @@ -40,6 +41,12 @@ public AerospikeException(int resultCode, String message) {
this.resultCode = resultCode;
}

public AerospikeException(int resultCode, String message, int subcode) {
super(message);
this.resultCode = resultCode;
this.subcode = subcode;
}

public AerospikeException(int resultCode, Throwable e) {
super(e);
this.resultCode = resultCode;
Expand Down Expand Up @@ -184,6 +191,27 @@ public final int getResultCode() {
return resultCode;
}

/**
* Get the server-supplied error subcode, or {@link SubCode#NONE} (0) when the
* server did not return one (verbosity disabled, or the failing branch had no
* dispatchable subcode).
* <p>
* A subcode is only meaningful when interpreted together with
* {@link #getResultCode()}: subcode integer values are scoped to their parent
* result code and are NOT globally unique. Dispatch on the
* {@code (resultCode, subcode)} pair. See {@link SubCode}.
*/
public final int getSubcode() {
return subcode;
}

/**
* Set the server-supplied error subcode.
*/
public final void setSubcode(int subcode) {
this.subcode = subcode;
}

/**
* Get number of attempts before failing.
*/
Expand Down
218 changes: 218 additions & 0 deletions client/src/com/aerospike/client/SubCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* Copyright 2012-2026 Aerospike, Inc.
*
* Portions may be licensed to Aerospike, Inc. under one or more contributor
* license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.aerospike.client;

/**
* Server error detail subcodes.
* <p>
* When extended error detail is requested (see
* {@link com.aerospike.client.policy.Policy#errorDetailVerbosity}), the server may
* attach a numeric subcode to a failure response. The subcode is surfaced on
* {@link AerospikeException#getSubcode()}.
* <p>
* <b>Match on the {@code (resultCode, subcode)} pair.</b> Subcode integer values are
* scoped to their parent {@link ResultCode} and are <b>not</b> globally unique — the
* value {@code 1}, for example, recurs under every parent status. A subcode is only
* meaningful when interpreted together with the result code. Always check the result
* code first:
* <pre>{@code
* catch (AerospikeException ae) {
* if (ae.getResultCode() == ResultCode.OP_NOT_APPLICABLE &&
* ae.getSubcode() == SubCode.OPNOT_CDT_BOUNDED_LIST_OVERFLOW) {
* // roll to a fresh partition / apply backpressure
* }
* }
* }</pre>
* <p>
* {@link #NONE} (0) means "no subcode" — it is reserved universally and is the value
* returned when the server did not send a subcode (verbosity disabled, or the failing
* branch had no dispatchable subcode).
* <p>
* This catalogue mirrors the server's per-status enums in
* {@code as/include/base/proto.h} and is server-version-specific. It is append-only:
* published values are immutable and are never renumbered or reused. New failure modes
* get new values appended to their group. Treat any subcode value not declared here as
* an opaque integer rather than assuming it is absent.
*/
public final class SubCode {
/**
* No subcode (universal). Returned when the server did not supply a subcode.
*/
public static final int NONE = 0;

//-------------------------------------------------------
// Pairs with ResultCode.PARAMETER_ERROR (4) [AS_ERR_PARAMETER]
//-------------------------------------------------------

/** Per-record TTL exceeds the namespace's max-ttl. */
public static final int PARAM_TTL_INVALID = 1;

/** Bit op offset lands past the blob (or above the proto cap). */
public static final int PARAM_BITS_OFFSET_OUT_OF_RANGE = 2;

/** Bit op size is out of range (e.g. zero, or too large). */
public static final int PARAM_BITS_SIZE_OUT_OF_RANGE = 3;

/** Blob resize would exceed the maximum blob size. */
public static final int PARAM_BITS_RESIZE_EXCEEDED = 4;

/** Write would exceed the per-record bin-count limit (write path). */
public static final int PARAM_BIN_COUNT_TOO_LARGE = 5;

/** String op wire/expression args malformed or out of range. */
public static final int PARAM_STRING_OP_PARAMS_INVALID = 6;

/** String op code or modifier/read class mismatch on the wire path. */
public static final int PARAM_STRING_OP_INVALID = 7;

/** String context-eval path malformed. */
public static final int PARAM_STRING_CTX_NOT_APPLICABLE = 8;

/** String modify/read index or code-point range out of bounds. */
public static final int PARAM_STRING_INDEX_OUT_OF_BOUNDS = 9;

/** String regex pattern invalid (compile / ICU failure). */
public static final int PARAM_STRING_REGEX_INVALID = 10;

/** String or string op argument is not valid UTF-8. */
public static final int PARAM_STRING_UTF8_INVALID = 11;

//-------------------------------------------------------
// Pairs with ResultCode.PARTITION_UNAVAILABLE (11) [AS_ERR_UNAVAILABLE]
//-------------------------------------------------------

/** Cluster is still resolving initial partition balance at startup. */
public static final int UNAVAIL_INITIAL_BALANCE_UNRESOLVED = 1;

/** A needed replica is unavailable (likely a partition split). */
public static final int UNAVAIL_REPLICA_UNAVAILABLE = 2;

//-------------------------------------------------------
// Pairs with ResultCode.UNSUPPORTED_FEATURE (16) [AS_ERR_UNSUPPORTED_FEATURE]
//-------------------------------------------------------

/** MRT attempted against a non-SC (AP) namespace. */
public static final int UNSUPP_FEAT_MRT_REQUIRES_STRONG_CONSISTENCY = 1;

/** Requested feature is unsupported in this context (generic). */
public static final int UNSUPP_FEAT_GENERIC = 2;

//-------------------------------------------------------
// Pairs with ResultCode.BIN_NOT_FOUND (17) [AS_ERR_BIN_NOT_FOUND]
//-------------------------------------------------------

/** HLL op needs an existing bin and can't auto-create one. */
public static final int BIN_NOT_FOUND_HLL_CANNOT_CREATE_WITH_OP = 1;

/** String modify on a missing bin (non-NO_FAIL path). */
public static final int BIN_NOT_FOUND_STRING_VALUE_NOT_FOUND = 2;

//-------------------------------------------------------
// Pairs with ResultCode.BIN_NAME_TOO_LONG (21) [AS_ERR_BIN_NAME]
//-------------------------------------------------------

/** Write would exceed the per-record bin-count limit (UDF path). */
public static final int BIN_NAME_COUNT_TOO_LARGE = 1;

//-------------------------------------------------------
// Pairs with ResultCode.FAIL_FORBIDDEN (22) [AS_ERR_FORBIDDEN]
//-------------------------------------------------------

/** Write bounced by an XDR ship filter at the destination. */
public static final int FORBID_XDR_FILTER_BLOCKED = 1;

/** Set-level record-count stop-writes limit reached. */
public static final int FORBID_SET_COUNT_STOP_WRITES = 2;

/** Set-level size stop-writes limit reached. */
public static final int FORBID_SET_SIZE_STOP_WRITES = 3;

/** Writes stopped due to cluster clock skew. */
public static final int FORBID_CLOCK_SKEW_STOP_WRITES = 4;

/** REPLACE / CREATE_OR_REPLACE forbidden while resolving conflicts. */
public static final int FORBID_REPLACE_CONFLICT_RESOLVING = 5;

/** Write forbidden because the set/namespace is mid-truncate. */
public static final int FORBID_TRUNCATED = 6;

// Note: server subcodes 7 and 9 in this family are retired (masking violations
// return ROLE_VIOLATION, not FORBIDDEN) and are intentionally not declared.

/** Non-durable delete forbidden (would violate durability). */
public static final int FORBID_DURABILITY_VIOLATION = 8;

//-------------------------------------------------------
// Pairs with ResultCode.OP_NOT_APPLICABLE (26) [AS_ERR_OP_NOT_APPLICABLE]
//-------------------------------------------------------

/** List index is outside the current element range. */
public static final int OPNOT_CDT_INDEX_OUT_OF_BOUNDS = 1;

/** Requested rank is past the current population. */
public static final int OPNOT_CDT_RANK_OUT_OF_BOUNDS = 2;

/** Insert would exceed an ordered+bounded list's cap. */
public static final int OPNOT_CDT_BOUNDED_LIST_OVERFLOW = 3;

/** HLL op needs index_bits but the sketch has none set. */
public static final int OPNOT_HLL_INDEX_BITS_UNSET = 4;

/** Union needs to reduce index_bits but folding isn't allowed. */
public static final int OPNOT_HLL_CANNOT_REDUCE_INDEX_BITS = 5;

/** As above, for the minhash dimension. */
public static final int OPNOT_HLL_CANNOT_REDUCE_MINHASH_BITS = 6;

/** Fold blocked because the sketch carries minhash bits. */
public static final int OPNOT_HLL_CANNOT_FOLD_MINHASH = 7;

/** Fold target index_bits >= current (fold can only reduce). */
public static final int OPNOT_HLL_FOLD_INDEX_BITS_TOO_LARGE = 8;

/** Intersect inputs have mismatched minhash parameters. */
public static final int OPNOT_HLL_INTERSECT_MINHASH_MISMATCH = 9;

/** String to numeric conversion failed (strtoll/strtod). */
public static final int OPNOT_STRING_CONVERSION_FAILED = 10;

/** Source blob/string is not valid UTF-8 for an OP_NOT_APPLICABLE path. */
public static final int OPNOT_STRING_UTF8_INVALID = 11;

//-------------------------------------------------------
// Pairs with ResultCode.FILTERED_OUT (27) [AS_ERR_FILTERED_OUT]
//-------------------------------------------------------

/** Record filtered out by a metadata-only filter expression. */
public static final int FILTERED_META = 1;

/** Record filtered out by a bin-reading filter expression. */
public static final int FILTERED_BINS = 2;

//-------------------------------------------------------
// Pairs with ResultCode.MRT_BLOCKED (120) [AS_ERR_MRT_BLOCKED]
//-------------------------------------------------------

/** Record is provisionally locked by another MRT. */
public static final int MRT_BLOCKED_RECORD_LOCKED = 1;

/** Op belongs to a different MRT than the one holding the lock. */
public static final int MRT_BLOCKED_ID_MISMATCH = 2;

private SubCode() {
}
}
5 changes: 3 additions & 2 deletions client/src/com/aerospike/client/async/AsyncDelete.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.aerospike.client.Key;
import com.aerospike.client.ResultCode;
import com.aerospike.client.cluster.Cluster;
import com.aerospike.client.command.RecordParser;
import com.aerospike.client.listener.DeleteListener;
import com.aerospike.client.policy.WritePolicy;

Expand Down Expand Up @@ -53,13 +54,13 @@ protected boolean parseResult() {

if (resultCode == ResultCode.FILTERED_OUT) {
if (policy.failOnFilteredOut) {
throw new AerospikeException(resultCode);
throw RecordParser.toException(resultCode, serverMessage, serverSubcode);
}
existed = true;
return true;
}

throw new AerospikeException(resultCode);
throw RecordParser.toException(resultCode, serverMessage, serverSubcode);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions client/src/com/aerospike/client/async/AsyncExecute.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ record = rp.parseRecord(false);

if (rp.resultCode == ResultCode.FILTERED_OUT) {
if (policy.failOnFilteredOut) {
throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}
return true;
}

throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}

private void handleUdfError(int resultCode) {
Expand Down
4 changes: 2 additions & 2 deletions client/src/com/aerospike/client/async/AsyncExists.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ protected boolean parseResult() {

if (rp.resultCode == ResultCode.FILTERED_OUT) {
if (policy.failOnFilteredOut) {
throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}
exists = true;
return true;
}

throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions client/src/com/aerospike/client/async/AsyncOperateWrite.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ record = rp.parseRecord(true);

if (rp.resultCode == ResultCode.FILTERED_OUT) {
if (policy.failOnFilteredOut) {
throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}
return true;
}

throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions client/src/com/aerospike/client/async/AsyncRead.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ protected final boolean parseResult() {

if (rp.resultCode == ResultCode.FILTERED_OUT) {
if (policy.failOnFilteredOut) {
throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}
return true;
}

throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions client/src/com/aerospike/client/async/AsyncReadHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ record = new Record(null, rp.generation, rp.expiration);

if (rp.resultCode == ResultCode.FILTERED_OUT) {
if (policy.failOnFilteredOut) {
throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}
return true;
}

throw new AerospikeException(rp.resultCode);
throw RecordParser.toException(rp.resultCode, rp.serverMessage, rp.serverSubcode);
}

@Override
Expand Down
Loading
Loading