This is an automated email from the ASF dual-hosted git repository.

sk0x50 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 94b44efda IGNITE-14931 Added support error groups, error codes and 
tracingIds. Fixes #904
94b44efda is described below

commit 94b44efda0956cae96abdff81e861c2b2b8509ff
Author: Slava Koptilin <[email protected]>
AuthorDate: Mon Jul 4 20:29:51 2022 +0300

    IGNITE-14931 Added support error groups, error codes and tracingIds. Fixes 
#904
---
 .../ignite/lang/ColumnAlreadyExistsException.java  |   4 +-
 .../ignite/lang/ColumnNotFoundException.java       |  13 +-
 .../apache/ignite/lang/IgniteCheckedException.java | 203 +++++++++++++++++++
 .../org/apache/ignite/lang/IgniteException.java    | 191 +++++++++++++++++-
 .../ignite/lang/TableAlreadyExistsException.java   |   4 +-
 .../apache/ignite/lang/TableNotFoundException.java |   4 +-
 modules/client-common/pom.xml                      |   6 +
 .../client/proto/ClientMessageDecoderTest.java     |   6 +-
 modules/client-handler/pom.xml                     |   6 +
 .../ignite/client/handler/ItClientHandlerTest.java |   6 +-
 .../src/test/java/ClientResourceRegistryTest.java  |  11 +-
 .../ignite/internal/client/table/ClientSchema.java |   3 +-
 .../apache/ignite/client/ClientComputeTest.java    |   4 +-
 .../ignite/client/ClientKeyValueViewTest.java      |   4 +-
 .../apache/ignite/client/ClientRecordViewTest.java |   4 +-
 .../org/apache/ignite/client/ClientTableTest.java  |   4 +-
 .../org/apache/ignite/client/ClientTupleTest.java  |  14 +-
 .../apache/ignite/client/ConfigurationTest.java    |   9 +-
 .../org/apache/ignite/client/ConnectionTest.java   |   6 +-
 .../org/apache/ignite/client/RetryPolicyTest.java  |   6 +-
 .../java/org/apache/ignite/lang/ErrorGroup.java    | 224 +++++++++++++++++++++
 .../java/org/apache/ignite/lang/ErrorGroups.java   |  47 +++++
 .../lang/IgniteInternalCheckedException.java       | 217 +++++++++++++++++++-
 .../ignite/lang/IgniteInternalException.java       | 191 +++++++++++++++++-
 .../apache/ignite/lang/IgniteStringFormatter.java  |   2 +-
 .../internal/causality/VersionedValueTest.java     |   5 +-
 .../marshal/BestEffortInstantiationTest.java       |   3 +-
 .../marshal/DefaultSchemaMismatchHandlerTest.java  |   7 +-
 .../DefaultUserObjectMarshallerCommonTest.java     |   3 +-
 .../checkpoint/CheckpointMarkersStorageTest.java   |  14 +-
 .../store/FilePageStoreFactoryTest.java            |   4 +-
 .../store/FilePageStoreManagerTest.java            |  10 +-
 .../store/LongOperationAsyncExecutorTest.java      |   9 +-
 .../Apache.Ignite.Tests/ClientSocketTests.cs       |   2 +-
 .../Apache.Ignite.Tests/Compute/ComputeTests.cs    |   4 +-
 .../Table/RecordViewBinaryTests.cs                 |   2 +-
 .../Table/RecordViewPocoTests.cs                   |   2 +-
 .../runner/app/client/ItThinClientComputeTest.java |   2 +-
 .../app/client/ItThinClientTransactionsTest.java   |   9 +-
 .../sql/engine/exec/MockedStructuresTest.java      |   7 +-
 40 files changed, 1172 insertions(+), 100 deletions(-)

diff --git 
a/modules/api/src/main/java/org/apache/ignite/lang/ColumnAlreadyExistsException.java
 
b/modules/api/src/main/java/org/apache/ignite/lang/ColumnAlreadyExistsException.java
index 89f02822c..fe6c0b391 100644
--- 
a/modules/api/src/main/java/org/apache/ignite/lang/ColumnAlreadyExistsException.java
+++ 
b/modules/api/src/main/java/org/apache/ignite/lang/ColumnAlreadyExistsException.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.lang;
 
+import static 
org.apache.ignite.lang.ErrorGroups.Table.COLUMN_ALREADY_EXISTS_ERR;
+
 /**
  * This exception is thrown when a new column failed to be created, because 
another column with the same name already exists.
  */
@@ -27,6 +29,6 @@ public class ColumnAlreadyExistsException extends 
IgniteException {
      * @param name Column name.
      */
     public ColumnAlreadyExistsException(String name) {
-        super(IgniteStringFormatter.format("Column already exists [name={}]", 
name));
+        super(COLUMN_ALREADY_EXISTS_ERR, "Column already exists [name=" + name 
+ ']');
     }
 }
diff --git 
a/modules/api/src/main/java/org/apache/ignite/lang/ColumnNotFoundException.java 
b/modules/api/src/main/java/org/apache/ignite/lang/ColumnNotFoundException.java
index c0f578d05..fa0db323c 100644
--- 
a/modules/api/src/main/java/org/apache/ignite/lang/ColumnNotFoundException.java
+++ 
b/modules/api/src/main/java/org/apache/ignite/lang/ColumnNotFoundException.java
@@ -17,10 +17,21 @@
 
 package org.apache.ignite.lang;
 
+import static org.apache.ignite.lang.ErrorGroups.Table.COLUMN_NOT_FOUND_ERR;
+
 /**
  * Exception is thrown when appropriate column is not found.
  */
 public class ColumnNotFoundException extends IgniteException {
+    /**
+     * Create a new exception with given column name.
+     *
+     * @param columnName Column name.
+     */
+    public ColumnNotFoundException(String columnName) {
+        super(COLUMN_NOT_FOUND_ERR, "Column '" + columnName + "' does not 
exist");
+    }
+
     /**
      * Create a new exception with given column name.
      *
@@ -28,6 +39,6 @@ public class ColumnNotFoundException extends IgniteException {
      * @param fullName Table canonical name.
      */
     public ColumnNotFoundException(String columnName, String fullName) {
-        super(IgniteStringFormatter.format("Column '{}' does not exist in 
table '{}'", columnName, fullName));
+        super(COLUMN_NOT_FOUND_ERR, "Column '" + columnName + "' does not 
exist in table '" + fullName + '\'');
     }
 }
diff --git 
a/modules/api/src/main/java/org/apache/ignite/lang/IgniteCheckedException.java 
b/modules/api/src/main/java/org/apache/ignite/lang/IgniteCheckedException.java
new file mode 100755
index 000000000..88a8eeb16
--- /dev/null
+++ 
b/modules/api/src/main/java/org/apache/ignite/lang/IgniteCheckedException.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.lang;
+
+import static org.apache.ignite.lang.ErrorGroup.errorGroupByCode;
+import static org.apache.ignite.lang.ErrorGroup.errorMessage;
+import static org.apache.ignite.lang.ErrorGroup.errorMessageFromCause;
+import static org.apache.ignite.lang.ErrorGroup.extractErrorCode;
+import static org.apache.ignite.lang.ErrorGroup.extractGroupCode;
+
+import java.util.UUID;
+
+/**
+ * General Ignite exception. This exception is used to indicate any error 
condition within the node.
+ */
+public class IgniteCheckedException extends Exception {
+    /** Serial version uid. */
+    private static final long serialVersionUID = 0L;
+
+    /** Name of the error group. */
+    private final String groupName;
+
+    /**
+     * Error code which contains information about error group and code, where 
code is unique within the group.
+     * The structure of a code is shown in the following diagram:
+     * +------------+--------------+
+     * |  16 bits   |    16 bits   |
+     * +------------+--------------+
+     * | Group Code |  Error Code  |
+     * +------------+--------------+
+     */
+    private final int code;
+
+    /** Unique identifier of this exception that should help locating the 
error message in a log file. */
+    private final UUID traceId;
+
+    /**
+     * Creates a new exception with the given error code.
+     *
+     * @param code Full error code.
+     */
+    public IgniteCheckedException(int code) {
+        this(UUID.randomUUID(), code);
+    }
+
+    /**
+     * Creates a new exception with the given trace id and error code.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     */
+    public IgniteCheckedException(UUID traceId, int code) {
+        super(errorMessage(traceId, code, null));
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code and detail message.
+     *
+     * @param code Full error code.
+     * @param message Detail message.
+     */
+    public IgniteCheckedException(int code, String message) {
+        this(UUID.randomUUID(), code, message);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code and detail 
message.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Detail message.
+     */
+    public IgniteCheckedException(UUID traceId, int code, String message) {
+        super(errorMessage(traceId, code, message));
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code and cause.
+     *
+     * @param code Full error code.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteCheckedException(int code, Throwable cause) {
+        this(UUID.randomUUID(), code, cause);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code and cause.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteCheckedException(UUID traceId, int code, Throwable cause) {
+        super(errorMessageFromCause(traceId, code, cause), cause);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code, detail message and 
cause.
+     *
+     * @param code Full error code.
+     * @param message Detail message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteCheckedException(int code, String message, Throwable cause) {
+        this(UUID.randomUUID(), code, message, cause);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code, detail 
message and cause.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Detail message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteCheckedException(UUID traceId, int code, String message, 
Throwable cause) {
+        super(errorMessage(traceId, code, message), cause);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Returns a group name of this error.
+     *
+     * @see #groupCode()
+     * @see #code()
+     * @return Group name.
+     */
+    public String groupName() {
+        return groupName;
+    }
+
+    /**
+     * Returns a full error code which includes a group of the error and code 
which is uniquely identifies a problem within the group.
+     * This is a combination of two most-significant bytes that represent the 
error group and
+     * two least-significant bytes for the error code.
+     *
+     * @return Full error code.
+     */
+    public int code() {
+        return code;
+    }
+
+    /**
+     * Returns error group.
+     *
+     * @see #code()
+     * @return Error group.
+     */
+    public int groupCode() {
+        return extractGroupCode(code);
+    }
+
+    /**
+     * Returns error code that uniquely identifies a problem within a group.
+     *
+     * @see #code()
+     * @see #groupCode()
+     * @return Error code.
+     */
+    public int errorCode() {
+        return extractErrorCode(code);
+    }
+
+    /**
+     * Returns an unique identifier of this exception.
+     *
+     * @return Unique identifier of this exception.
+     */
+    public UUID traceId() {
+        return traceId;
+    }
+}
diff --git 
a/modules/api/src/main/java/org/apache/ignite/lang/IgniteException.java 
b/modules/api/src/main/java/org/apache/ignite/lang/IgniteException.java
index 727c10abd..7fe71e413 100644
--- a/modules/api/src/main/java/org/apache/ignite/lang/IgniteException.java
+++ b/modules/api/src/main/java/org/apache/ignite/lang/IgniteException.java
@@ -17,6 +17,14 @@
 
 package org.apache.ignite.lang;
 
+import static org.apache.ignite.lang.ErrorGroup.errorGroupByCode;
+import static org.apache.ignite.lang.ErrorGroup.errorMessage;
+import static org.apache.ignite.lang.ErrorGroup.errorMessageFromCause;
+import static org.apache.ignite.lang.ErrorGroup.extractErrorCode;
+import static org.apache.ignite.lang.ErrorGroup.extractGroupCode;
+import static org.apache.ignite.lang.ErrorGroups.Common.UNKNOWN_ERR;
+
+import java.util.UUID;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -26,11 +34,29 @@ public class IgniteException extends RuntimeException {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
+    /** Name of the error group. */
+    private final String groupName;
+
+    /**
+     * Error code which contains information about error group and code, where 
code is unique within the group.
+     * The structure of a code is shown in the following diagram:
+     * +------------+--------------+
+     * |  16 bits   |    16 bits   |
+     * +------------+--------------+
+     * | Group Code |  Error Code  |
+     * +------------+--------------+
+     */
+    private final int code;
+
+    /** Unique identifier of this exception that should help locating the 
error message in a log file. */
+    private final UUID traceId;
+
     /**
      * Creates an empty exception.
      */
+    @Deprecated
     public IgniteException() {
-        // No-op.
+        this(UNKNOWN_ERR);
     }
 
     /**
@@ -38,8 +64,9 @@ public class IgniteException extends RuntimeException {
      *
      * @param msg Error message.
      */
+    @Deprecated
     public IgniteException(String msg) {
-        super(msg);
+        this(UNKNOWN_ERR, msg);
     }
 
     /**
@@ -47,8 +74,9 @@ public class IgniteException extends RuntimeException {
      *
      * @param cause Non-null throwable cause.
      */
+    @Deprecated
     public IgniteException(Throwable cause) {
-        this(cause.getMessage(), cause);
+        this(UNKNOWN_ERR, cause);
     }
 
     /**
@@ -57,13 +85,160 @@ public class IgniteException extends RuntimeException {
      * @param msg   Error message.
      * @param cause Optional nested exception (can be {@code null}).
      */
+    @Deprecated
     public IgniteException(String msg, @Nullable Throwable cause) {
-        super(msg, cause);
+        this(UNKNOWN_ERR, msg, cause);
+    }
+
+    /**
+     * Creates a new exception with the given error code.
+     *
+     * @param code Full error code.
+     */
+    public IgniteException(int code) {
+        this(UUID.randomUUID(), code);
+    }
+
+    /**
+     * Creates a new exception with the given trace id and error code.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     */
+    public IgniteException(UUID traceId, int code) {
+        super(errorMessage(traceId, code, null));
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return getClass() + ": " + getMessage();
+    /**
+     * Creates a new exception with the given error code and detail message.
+     *
+     * @param code Full error code.
+     * @param message Detail message.
+     */
+    public IgniteException(int code, String message) {
+        this(UUID.randomUUID(), code, message);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code and detail 
message.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Detail message.
+     */
+    public IgniteException(UUID traceId, int code, String message) {
+        super(errorMessage(traceId, code, message));
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code and cause.
+     *
+     * @param code Full error code.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteException(int code, Throwable cause) {
+        this(UUID.randomUUID(), code, cause);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code and cause.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteException(UUID traceId, int code, Throwable cause) {
+        super(errorMessageFromCause(traceId, code, cause), cause);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code, detail message and 
cause.
+     *
+     * @param code Full error code.
+     * @param message Detail message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteException(int code, String message, Throwable cause) {
+        this(UUID.randomUUID(), code, message, cause);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code, detail 
message and cause.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Detail message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteException(UUID traceId, int code, String message, Throwable 
cause) {
+        super(errorMessage(traceId, code, message), cause);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Returns a group name of this error.
+     *
+     * @see #groupCode()
+     * @see #code()
+     * @return Group name.
+     */
+    public String groupName() {
+        return groupName;
+    }
+
+    /**
+     * Returns a full error code which includes a group of the error and code 
which is uniquely identifies a problem within the group.
+     * This is a combination of two most-significant bytes that represent the 
error group and
+     * two least-significant bytes for the error code.
+     *
+     * @return Full error code.
+     */
+    public int code() {
+        return code;
+    }
+
+    /**
+     * Returns error group.
+     *
+     * @see #code()
+     * @return Error group.
+     */
+    public int groupCode() {
+        return extractGroupCode(code);
+    }
+
+    /**
+     * Returns error code that uniquely identifies a problem within a group.
+     *
+     * @see #code()
+     * @see #groupCode()
+     * @return Error code.
+     */
+    public int errorCode() {
+        return extractErrorCode(code);
+    }
+
+    /**
+     * Returns an unique identifier of this exception.
+     *
+     * @return Unique identifier of this exception.
+     */
+    public UUID traceId() {
+        return traceId;
     }
 }
diff --git 
a/modules/api/src/main/java/org/apache/ignite/lang/TableAlreadyExistsException.java
 
b/modules/api/src/main/java/org/apache/ignite/lang/TableAlreadyExistsException.java
index 058d0fc94..e4fd9e176 100644
--- 
a/modules/api/src/main/java/org/apache/ignite/lang/TableAlreadyExistsException.java
+++ 
b/modules/api/src/main/java/org/apache/ignite/lang/TableAlreadyExistsException.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.lang;
 
+import static 
org.apache.ignite.lang.ErrorGroups.Table.TABLE_ALREADY_EXISTS_ERR;
+
 /**
  * This exception is thrown when a new table failed to be created, because a 
table with same name already exists.
  */
@@ -27,6 +29,6 @@ public class TableAlreadyExistsException extends 
IgniteException {
      * @param name Table name.
      */
     public TableAlreadyExistsException(String name) {
-        super(IgniteStringFormatter.format("Table already exists [name={}]", 
name));
+        super(TABLE_ALREADY_EXISTS_ERR, "Table already exists [name=" + name + 
']');
     }
 }
diff --git 
a/modules/api/src/main/java/org/apache/ignite/lang/TableNotFoundException.java 
b/modules/api/src/main/java/org/apache/ignite/lang/TableNotFoundException.java
index c066c9d81..c4634f81c 100644
--- 
a/modules/api/src/main/java/org/apache/ignite/lang/TableNotFoundException.java
+++ 
b/modules/api/src/main/java/org/apache/ignite/lang/TableNotFoundException.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.lang;
 
+import static org.apache.ignite.lang.ErrorGroups.Table.TABLE_NOT_FOUND_ERR;
+
 /**
  * Exception is thrown when appropriate table can`t be found.
  */
@@ -27,6 +29,6 @@ public class TableNotFoundException extends IgniteException {
      * @param name Table name.
      */
     public TableNotFoundException(String name) {
-        super(IgniteStringFormatter.format("Table does not exist [name={}]", 
name));
+        super(TABLE_NOT_FOUND_ERR, "Table does not exist [name=" + name + ']');
     }
 }
diff --git a/modules/client-common/pom.xml b/modules/client-common/pom.xml
index 755102e47..582912c67 100644
--- a/modules/client-common/pom.xml
+++ b/modules/client-common/pom.xml
@@ -94,6 +94,12 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest</artifactId>
+            <scope>test</scope>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.ignite</groupId>
             <artifactId>ignite-core</artifactId>
diff --git 
a/modules/client-common/src/test/java/org/apache/ignite/internal/client/proto/ClientMessageDecoderTest.java
 
b/modules/client-common/src/test/java/org/apache/ignite/internal/client/proto/ClientMessageDecoderTest.java
index be5309a0f..566bf67a9 100644
--- 
a/modules/client-common/src/test/java/org/apache/ignite/internal/client/proto/ClientMessageDecoderTest.java
+++ 
b/modules/client-common/src/test/java/org/apache/ignite/internal/client/proto/ClientMessageDecoderTest.java
@@ -17,8 +17,9 @@
 
 package org.apache.ignite.internal.client.proto;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -51,8 +52,7 @@ public class ClientMessageDecoderTest {
 
         var t = assertThrows(IgniteException.class, () -> decode(buf));
 
-        assertEquals("Invalid magic header in thin client connection. Expected 
'IGNI', but was 'BEEF'.",
-                t.getMessage());
+        assertThat(t.getMessage(), containsString("Invalid magic header in 
thin client connection. Expected 'IGNI', but was 'BEEF'."));
     }
 
     private static byte[] getMagicWithPayload() {
diff --git a/modules/client-handler/pom.xml b/modules/client-handler/pom.xml
index 97806b1f6..c007bbb38 100644
--- a/modules/client-handler/pom.xml
+++ b/modules/client-handler/pom.xml
@@ -124,6 +124,12 @@
             <artifactId>mockito-junit-jupiter</artifactId>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/modules/client-handler/src/integrationTest/java/org/apache/ignite/client/handler/ItClientHandlerTest.java
 
b/modules/client-handler/src/integrationTest/java/org/apache/ignite/client/handler/ItClientHandlerTest.java
index 94bbd7e1f..425eeb263 100644
--- 
a/modules/client-handler/src/integrationTest/java/org/apache/ignite/client/handler/ItClientHandlerTest.java
+++ 
b/modules/client-handler/src/integrationTest/java/org/apache/ignite/client/handler/ItClientHandlerTest.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.client.handler;
 
 import static 
org.apache.ignite.configuration.annotation.ConfigurationType.LOCAL;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -184,12 +186,12 @@ public class ItClientHandlerTest {
             final var err = unpacker.unpackString();
 
             assertArrayEquals(MAGIC, magic);
-            assertEquals(32, len);
+            assertEquals(88, len);
             assertEquals(3, major);
             assertEquals(0, minor);
             assertEquals(0, patch);
             assertEquals(1, errorCode);
-            assertEquals("Unsupported version: 2.8.0", err);
+            assertThat(err, containsString("Unsupported version: 2.8.0"));
         }
     }
 
diff --git 
a/modules/client-handler/src/test/java/ClientResourceRegistryTest.java 
b/modules/client-handler/src/test/java/ClientResourceRegistryTest.java
index e576a364a..54f13ac37 100644
--- a/modules/client-handler/src/test/java/ClientResourceRegistryTest.java
+++ b/modules/client-handler/src/test/java/ClientResourceRegistryTest.java
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -43,7 +45,7 @@ public class ClientResourceRegistryTest {
         assertSame(resource, removed);
 
         var ex = assertThrows(IgniteInternalException.class, () -> 
reg.get(id));
-        assertEquals("Failed to find resource with id: 1", ex.getMessage());
+        assertThat(ex.getMessage(), containsString("Failed to find resource 
with id: 1"));
     }
 
     @Test
@@ -58,13 +60,14 @@ public class ClientResourceRegistryTest {
 
         assertEquals(2, closed.get());
 
+        String expected = "Resource registry is closed.";
         var ex = assertThrows(IgniteInternalCheckedException.class, () -> 
reg.put(new ClientResource(1, null)));
-        assertEquals("Resource registry is closed.", ex.getMessage());
+        assertThat(ex.getMessage(), containsString(expected));
 
         ex = assertThrows(IgniteInternalCheckedException.class, () -> 
reg.get(0));
-        assertEquals("Resource registry is closed.", ex.getMessage());
+        assertThat(ex.getMessage(), containsString(expected));
 
         ex = assertThrows(IgniteInternalCheckedException.class, () -> 
reg.remove(0));
-        assertEquals("Resource registry is closed.", ex.getMessage());
+        assertThat(ex.getMessage(), containsString(expected));
     }
 }
diff --git 
a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientSchema.java
 
b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientSchema.java
index d37992fdd..88fbbc698 100644
--- 
a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientSchema.java
+++ 
b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientSchema.java
@@ -42,6 +42,7 @@ import org.apache.ignite.internal.client.proto.TuplePart;
 import org.apache.ignite.internal.marshaller.BinaryMode;
 import org.apache.ignite.internal.marshaller.Marshaller;
 import org.apache.ignite.internal.marshaller.MarshallerColumn;
+import org.apache.ignite.lang.ColumnNotFoundException;
 import org.apache.ignite.lang.IgniteException;
 import org.apache.ignite.table.mapper.Mapper;
 import org.jetbrains.annotations.NotNull;
@@ -119,7 +120,7 @@ public class ClientSchema {
         var column = map.get(name);
 
         if (column == null) {
-            throw new IgniteException("Column is not present in schema: " + 
name);
+            throw new ColumnNotFoundException(name);
         }
 
         return column;
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/ClientComputeTest.java 
b/modules/client/src/test/java/org/apache/ignite/client/ClientComputeTest.java
index 0159d6111..b1dde3985 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/ClientComputeTest.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/ClientComputeTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.client;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -127,7 +129,7 @@ public class ClientComputeTest {
                     () -> client.compute().<String>executeColocated("bad-tbl", 
key, "job").join());
 
             assertInstanceOf(IgniteClientException.class, ex.getCause());
-            assertEquals("Table 'bad-tbl' does not exist.", 
ex.getCause().getMessage());
+            assertThat(ex.getCause().getMessage(), containsString("Table 
'bad-tbl' does not exist"));
         }
     }
 
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/ClientKeyValueViewTest.java
 
b/modules/client/src/test/java/org/apache/ignite/client/ClientKeyValueViewTest.java
index 4d89b3b2d..fda941c54 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/ClientKeyValueViewTest.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/ClientKeyValueViewTest.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.client;
 
 import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -198,7 +200,7 @@ public class ClientKeyValueViewTest extends 
AbstractClientTableTest {
 
         IgniteClientException e = assertThrows(IgniteClientException.class, () 
-> kvView.get(null, new NamePojo()));
 
-        assertEquals("No field found for column ID", e.getMessage());
+        assertThat(e.getMessage(), containsString("No field found for column 
ID"));
     }
 
     @Test
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/ClientRecordViewTest.java
 
b/modules/client/src/test/java/org/apache/ignite/client/ClientRecordViewTest.java
index ce09a17f5..5d0108cdb 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/ClientRecordViewTest.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/ClientRecordViewTest.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.client;
 
 import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -196,7 +198,7 @@ public class ClientRecordViewTest extends 
AbstractClientTableTest {
 
         IgniteClientException e = assertThrows(IgniteClientException.class, () 
-> recordView.get(null, new NamePojo()));
 
-        assertEquals("No field found for column ID", e.getMessage());
+        assertThat(e.getMessage(), containsString("No field found for column 
ID"));
     }
 
     @Test
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/ClientTableTest.java 
b/modules/client/src/test/java/org/apache/ignite/client/ClientTableTest.java
index 9f01e9f43..68ccf0f46 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/ClientTableTest.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/ClientTableTest.java
@@ -18,7 +18,7 @@
 package org.apache.ignite.client;
 
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.startsWith;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -394,7 +394,7 @@ public class ClientTableTest extends 
AbstractClientTableTest {
         Tuple tuple = Tuple.create().set("id", 1);
         var ex = assertThrows(IgniteClientException.class, () -> 
clientTable.recordView().get(null, tuple));
 
-        assertThat(ex.getMessage(), startsWith("Table does not exist: "));
+        assertThat(ex.getMessage(), containsString("Table does not exist: "));
         assertEquals(ClientErrorCode.TABLE_ID_DOES_NOT_EXIST, ex.errorCode());
     }
 }
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/ClientTupleTest.java 
b/modules/client/src/test/java/org/apache/ignite/client/ClientTupleTest.java
index 5205d33c4..9c253f448 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/ClientTupleTest.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/ClientTupleTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.client;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
@@ -36,7 +38,7 @@ import org.apache.ignite.internal.client.proto.ClientDataType;
 import org.apache.ignite.internal.client.table.ClientColumn;
 import org.apache.ignite.internal.client.table.ClientSchema;
 import org.apache.ignite.internal.client.table.ClientTuple;
-import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.lang.ColumnNotFoundException;
 import org.apache.ignite.table.Tuple;
 import org.junit.jupiter.api.Test;
 
@@ -93,17 +95,17 @@ public class ClientTupleTest {
 
     @Test
     public void testSetThrowsWhenColumnIsNotPresent() {
-        var ex = assertThrows(IgniteException.class, () -> 
getBuilder().set("x", "y"));
-        assertEquals("Column is not present in schema: X", ex.getMessage());
+        var ex = assertThrows(ColumnNotFoundException.class, () -> 
getBuilder().set("x", "y"));
+        assertThat(ex.getMessage(), containsString("Column 'X' does not 
exist"));
     }
 
     @Test
     public void testValueThrowsWhenColumnIsNotPresent() {
-        var ex = assertThrows(IgniteException.class, () -> 
getBuilder().value("x"));
-        assertEquals("Column is not present in schema: X", ex.getMessage());
+        var ex = assertThrows(ColumnNotFoundException.class, () -> 
getBuilder().value("x"));
+        assertThat(ex.getMessage(), containsString("Column 'X' does not 
exist"));
 
         var ex2 = assertThrows(IndexOutOfBoundsException.class, () -> 
getBuilder().value(100));
-        assertEquals("Index 100 out of bounds for length 2", ex2.getMessage());
+        assertThat(ex2.getMessage(), containsString("Index 100 out of bounds 
for length 2"));
     }
 
     @Test
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/ConfigurationTest.java 
b/modules/client/src/test/java/org/apache/ignite/client/ConfigurationTest.java
index ab734ae39..13f82199f 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/ConfigurationTest.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/ConfigurationTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.client;
 
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.either;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.startsWith;
@@ -42,7 +43,7 @@ public class ConfigurationTest extends AbstractClientTest {
 
         var ex = assertThrows(IgniteClientException.class, builder::build);
 
-        assertEquals("Empty addresses", ex.getMessage());
+        assertThat(ex.getMessage(), containsString("Empty addresses"));
     }
 
     @Test
@@ -52,9 +53,9 @@ public class ConfigurationTest extends AbstractClientTest {
 
         var ex = assertThrows(IgniteException.class, builder::build);
 
-        assertEquals(
-                "Failed to parse Ignite server address (port range contains 
invalid port 70000): 127.0.0.1:70000",
-                ex.getMessage());
+        assertThat(
+                ex.getMessage(),
+                containsString("Failed to parse Ignite server address (port 
range contains invalid port 70000): 127.0.0.1:70000"));
     }
 
     @Test
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/ConnectionTest.java 
b/modules/client/src/test/java/org/apache/ignite/client/ConnectionTest.java
index 75f2bd762..62a5ad162 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/ConnectionTest.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/ConnectionTest.java
@@ -18,8 +18,8 @@
 package org.apache.ignite.client;
 
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.endsWith;
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import org.apache.ignite.lang.IgniteException;
@@ -33,13 +33,13 @@ public class ConnectionTest extends AbstractClientTest {
     @Test
     public void testEmptyNodeAddress() {
         var ex = assertThrows(IgniteException.class, () -> testConnection(""));
-        assertEquals("Failed to parse Ignite server address (Address is 
empty): ", ex.getMessage());
+        assertThat(ex.getMessage(), containsString("Failed to parse Ignite 
server address (Address is empty): "));
     }
 
     @Test
     public void testNullNodeAddresses() {
         var ex = assertThrows(IgniteException.class, () -> 
testConnection(null, null));
-        assertEquals("Failed to parse Ignite server address (Address is 
empty): null", ex.getMessage());
+        assertThat(ex.getMessage(), containsString("Failed to parse Ignite 
server address (Address is empty): null"));
     }
 
     @Test
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/RetryPolicyTest.java 
b/modules/client/src/test/java/org/apache/ignite/client/RetryPolicyTest.java
index 30e60e9e2..acafc6a78 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/RetryPolicyTest.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/RetryPolicyTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.client;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertSame;
@@ -130,7 +132,7 @@ public class RetryPolicyTest {
         assertEquals(1, ctx.iteration());
         assertEquals(ClientOperationType.TABLES_GET, ctx.operation());
         assertSame(plc, ctx.configuration().retryPolicy());
-        assertEquals("Channel is closed", ctx.exception().getMessage());
+        assertThat(ctx.exception().getMessage(), containsString("Channel is 
closed"));
     }
 
     @Test
@@ -157,7 +159,7 @@ public class RetryPolicyTest {
             Transaction tx = client.transactions().begin();
 
             var ex = assertThrows(IgniteClientException.class, () -> 
recView.get(tx, Tuple.create().set("id", 1)));
-            assertEquals("Transaction context has been lost due to connection 
errors.", ex.getMessage());
+            assertThat(ex.getMessage(), containsString("Transaction context 
has been lost due to connection errors."));
 
             assertEquals(0, plc.invocations.size());
         }
diff --git a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroup.java 
b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroup.java
new file mode 100755
index 000000000..454f34ca2
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroup.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.lang;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
+import it.unimi.dsi.fastutil.ints.IntSet;
+import java.util.Locale;
+import java.util.UUID;
+
+/**
+ * This class represents a concept of error group. Error group defines a 
collection of errors that belong to a single semantic component.
+ * Each group can be identified by a name and an integer number that both must 
be unique across all error groups.
+ */
+public class ErrorGroup {
+    /** List of all registered error groups. */
+    private static final Int2ObjectMap<ErrorGroup> registeredGroups = new 
Int2ObjectOpenHashMap<>();
+
+    /** Group name. */
+    private final String groupName;
+
+    /** Group code. */
+    private final int groupCode;
+
+    /** Contains error codes for this error group. */
+    private final IntSet codes = new IntOpenHashSet();
+
+    /**
+     * Creates a new error group with the specified name and corresponding 
code.
+     *
+     * @param groupName Group name.
+     * @param groupCode Group code.
+     */
+    private ErrorGroup(String groupName, int groupCode) {
+        this.groupName = groupName;
+        this.groupCode = groupCode;
+    }
+
+    /**
+     * Returns a name of this group.
+     *
+     * @return Group name.
+     */
+    public String name() {
+        return groupName;
+    }
+
+    /**
+     * Returns a code of this group.
+     *
+     * @return Group code.
+     */
+    public int code() {
+        return groupCode;
+    }
+
+    /**
+     * Registers a new error code within this error group.
+     *
+     * @param errorCode Error code to be registered.
+     * @return Full error code which includes group code and specific error 
code.
+     * @throws IllegalArgumentException If the given {@code errorCode} is 
already registered
+     *      or {@code errorCode} is greater than 0xFFFF or less than or equal 
to 0.
+     */
+    public int registerErrorCode(int errorCode) {
+        if (errorCode <= 0 || errorCode > 0xFFFF) {
+            throw new IllegalArgumentException("Error code should be greater 
than 0 and less than or equal to 0xFFFF");
+        }
+
+        if (codes.contains(errorCode)) {
+            throw new IllegalArgumentException("Error code already registered 
[errorCode=" + errorCode + ", group=" + name() + ']');
+        }
+
+        codes.add(errorCode);
+
+        return (code() << 16) | (errorCode & 0xFFFF);
+    }
+
+    /**
+     * Checks that the given {@code code} is registered for this error group.
+     *
+     * @param code Full error code to be tested.
+     * @return {@code true} If the given {@code code} is registered for this 
error group.
+     */
+    public boolean isRegistered(ErrorGroup group, int code) {
+        return group.codes.contains(code);
+    }
+
+    /**
+     * Creates a new error group with the given {@code groupName} and {@code 
groupCode}.
+     *
+     * @param groupName Group name to be created.
+     * @param groupCode Group code to be created.
+     * @return New error group.
+     * @throws IllegalArgumentException If the specified name or group code 
already registered.
+     *      or {@code groupCode} is greater than 0xFFFF or less than or equal 
to 0.
+     */
+    public static synchronized ErrorGroup newGroup(String groupName, int 
groupCode) {
+        String grpName = groupName.toUpperCase(Locale.ENGLISH);
+
+        if (registeredGroups.containsKey(groupCode)) {
+            throw new IllegalArgumentException(
+                    "Error group already registered [groupName=" + groupName + 
", groupCode=" + groupCode
+                            + ", registeredGroup=" + 
registeredGroups.get(groupCode) + ']');
+        }
+
+        for (ErrorGroup group : registeredGroups.values()) {
+            if (group.name().equals(groupName)) {
+                throw new IllegalArgumentException(
+                    "Error group already registered [groupName=" + groupName + 
", groupCode=" + groupCode
+                            + ", registeredGroup=" + group + ']');
+            }
+        }
+
+        ErrorGroup newGroup = new ErrorGroup(grpName, groupCode);
+
+        registeredGroups.put(groupCode, newGroup);
+
+        return newGroup;
+    }
+
+    /**
+     * Returns group code extracted from the given full error code.
+     *
+     * @param code Full error code.
+     * @return Group code.
+     */
+    public static int extractGroupCode(int code) {
+        return code >>> 16;
+    }
+
+    /**
+     * Returns error code extracted from the given full error code.
+     *
+     * @param code Full error code.
+     * @return Error code.
+     */
+    public static int extractErrorCode(int code) {
+        return code & 0xFFFF;
+    }
+
+    /**
+     * Returns error group identified by the given {@code groupCode}.
+     *
+     * @param groupCode Group code
+     * @return Error Group.
+     */
+    public static ErrorGroup errorGroupByCode(int groupCode) {
+        return registeredGroups.get(groupCode);
+    }
+
+    /**
+     * Creates a new error message with predefined prefix.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Original message.
+     * @return New error message with predefined prefix.
+     */
+    public static String errorMessage(UUID traceId, int code, String message) {
+        return errorMessage(traceId, 
registeredGroups.get(extractGroupCode(code)).name(), code, message);
+    }
+
+    /**
+     * Creates a new error message with predefined prefix.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param groupName Group name.
+     * @param code Full error code.
+     * @param message Original message.
+     * @return New error message with predefined prefix.
+     */
+    public static String errorMessage(UUID traceId, String groupName, int 
code, String message) {
+        return "IGN-" + groupName + '-' + extractErrorCode(code) + " Trace 
ID:" + traceId + ((message != null) ? ' ' + message : "");
+    }
+
+    /**
+     * Creates a new error message with predefined prefix.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param cause Cause.
+     * @return New error message with predefined prefix.
+     */
+    public static String errorMessageFromCause(UUID traceId, int code, 
Throwable cause) {
+        return errorMessageFromCause(traceId, 
registeredGroups.get(extractGroupCode(code)).name(), code, cause);
+    }
+
+    /**
+     * Creates a new error message with predefined prefix.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param groupName Group name.
+     * @param code Full error code.
+     * @param cause Cause.
+     * @return New error message with predefined prefix.
+     */
+    public static String errorMessageFromCause(UUID traceId, String groupName, 
int code, Throwable cause) {
+        String c = (cause != null && cause.getMessage() != null) ? 
cause.getMessage() : null;
+
+        return (c != null && c.startsWith("IGN-")) ? c :  
errorMessage(traceId, groupName, code, c);
+    }
+
+    @Override
+    public String toString() {
+        return "ErrorGroup [name=" + name() + ", code=" + code() + ']';
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java 
b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
new file mode 100755
index 000000000..c5bb7d855
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.lang;
+
+/**
+ * Defines error groups and its errors.
+ */
+public class ErrorGroups {
+    /** Common error group. */
+    public static class Common {
+        /** Unknown error group. */
+        public static final ErrorGroup COMMON_ERR_GROUP = 
ErrorGroup.newGroup("CMN", 1);
+
+        /** Unknown error. */
+        public static int UNKNOWN_ERR = COMMON_ERR_GROUP.registerErrorCode(1);
+    }
+
+    /** Tables error group. */
+    public static class Table {
+        /** Table error group. */
+        public static final ErrorGroup TABLE_ERR_GROUP = 
ErrorGroup.newGroup("TBL", 2);
+
+        /** Table already exists. */
+        public static int TABLE_ALREADY_EXISTS_ERR = 
TABLE_ERR_GROUP.registerErrorCode(1);
+        /** Table not found. */
+        public static int TABLE_NOT_FOUND_ERR = 
TABLE_ERR_GROUP.registerErrorCode(2);
+        /** Column already exists. */
+        public static int COLUMN_ALREADY_EXISTS_ERR = 
TABLE_ERR_GROUP.registerErrorCode(3);
+        /** Column not found. */
+        public static int COLUMN_NOT_FOUND_ERR = 
TABLE_ERR_GROUP.registerErrorCode(4);
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/lang/IgniteInternalCheckedException.java
 
b/modules/core/src/main/java/org/apache/ignite/lang/IgniteInternalCheckedException.java
index 9cf54ca76..2dda664b2 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/lang/IgniteInternalCheckedException.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/lang/IgniteInternalCheckedException.java
@@ -17,6 +17,14 @@
 
 package org.apache.ignite.lang;
 
+import static org.apache.ignite.lang.ErrorGroup.errorGroupByCode;
+import static org.apache.ignite.lang.ErrorGroup.errorMessage;
+import static org.apache.ignite.lang.ErrorGroup.errorMessageFromCause;
+import static org.apache.ignite.lang.ErrorGroup.extractErrorCode;
+import static org.apache.ignite.lang.ErrorGroup.extractGroupCode;
+import static org.apache.ignite.lang.ErrorGroups.Common.UNKNOWN_ERR;
+
+import java.util.UUID;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -26,11 +34,152 @@ public class IgniteInternalCheckedException extends 
Exception {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
+    /** Name of the error group. */
+    private final String groupName;
+
+    /**
+     * Error code which contains information about error group and code, where 
code is unique within the group.
+     * The structure of a code is shown in the following diagram:
+     * +------------+--------------+
+     * |  16 bits   |    16 bits   |
+     * +------------+--------------+
+     * | Group Code |  Error Code  |
+     * +------------+--------------+
+     */
+    private final int code;
+
+    /** Unique identifier of this exception that should help locating the 
error message in a log file. */
+    private final UUID traceId;
+
+    /**
+     * Creates a new exception with the error code.
+     *
+     * @param code Full error code.
+     */
+    public IgniteInternalCheckedException(int code) {
+        this(UUID.randomUUID(), code);
+    }
+
+    /**
+     * Creates a new exception with the given trace id and error code.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     */
+    public IgniteInternalCheckedException(UUID traceId, int code) {
+        super(errorMessage(traceId, code, null));
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code and detail message.
+     *
+     * @param code Full error code.
+     * @param message Detail message.
+     */
+    public IgniteInternalCheckedException(int code, String message) {
+        this(UUID.randomUUID(), code, message);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code and detail 
message.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Detail message.
+     */
+    public IgniteInternalCheckedException(UUID traceId, int code, String 
message) {
+        super(errorMessage(traceId, code, message));
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code and cause.
+     *
+     * @param code Full error code.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteInternalCheckedException(int code, Throwable cause) {
+        this(UUID.randomUUID(), code, cause);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code and cause.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteInternalCheckedException(UUID traceId, int code, Throwable 
cause) {
+        super(errorMessageFromCause(traceId, code, cause), cause);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code, detail message and 
cause.
+     *
+     * @param code Full error code.
+     * @param message Detail message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteInternalCheckedException(int code, String message, Throwable 
cause) {
+        this(UUID.randomUUID(), code, message, cause);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code, detail 
message and cause.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Detail message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteInternalCheckedException(UUID traceId, int code, String 
message, Throwable cause) {
+        super(errorMessage(traceId, code, message), cause);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code, detail 
message and optional nested exception.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Error message.
+     * @param cause Optional nested exception (can be {@code null}).
+     * @param writableStackTrace Whether or not the stack trace should be 
writable.
+     */
+    public IgniteInternalCheckedException(
+            UUID traceId,
+            int code,
+            String message,
+            @Nullable Throwable cause,
+            boolean writableStackTrace
+    ) {
+        super(errorMessage(traceId, code, message), cause, true, 
writableStackTrace);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
     /**
      * Creates an empty exception.
      */
+    @Deprecated
     public IgniteInternalCheckedException() {
-        // No-op.
+        this(UNKNOWN_ERR);
     }
 
     /**
@@ -38,8 +187,9 @@ public class IgniteInternalCheckedException extends 
Exception {
      *
      * @param msg Error message.
      */
+    @Deprecated
     public IgniteInternalCheckedException(String msg) {
-        super(msg);
+        this(UNKNOWN_ERR, msg);
     }
 
     /**
@@ -47,8 +197,9 @@ public class IgniteInternalCheckedException extends 
Exception {
      *
      * @param cause Non-null throwable cause.
      */
+    @Deprecated
     public IgniteInternalCheckedException(Throwable cause) {
-        this(cause.getMessage(), cause);
+        this(UNKNOWN_ERR, cause);
     }
 
     /**
@@ -58,8 +209,9 @@ public class IgniteInternalCheckedException extends 
Exception {
      * @param cause              Optional nested exception (can be {@code 
null}).
      * @param writableStackTrace Whether or not the stack trace should be 
writable.
      */
+    @Deprecated
     public IgniteInternalCheckedException(String msg, @Nullable Throwable 
cause, boolean writableStackTrace) {
-        super(msg, cause, true, writableStackTrace);
+        this(UUID.randomUUID(), UNKNOWN_ERR, msg, cause, writableStackTrace);
     }
 
     /**
@@ -68,13 +220,60 @@ public class IgniteInternalCheckedException extends 
Exception {
      * @param msg   Error message.
      * @param cause Optional nested exception (can be {@code null}).
      */
+    @Deprecated
     public IgniteInternalCheckedException(String msg, @Nullable Throwable 
cause) {
-        super(msg, cause);
+        this(UNKNOWN_ERR, msg, cause);
+    }
+
+    /**
+     * Returns a group name of this error.
+     *
+     * @see #groupCode()
+     * @see #code()
+     * @return Group name.
+     */
+    public String groupName() {
+        return groupName;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return getClass() + ": " + getMessage();
+    /**
+     * Returns a full error code which includes a group of the error and code 
which is uniquely identifies a problem within the group.
+     * This is a combination of two most-significant bytes that represent the 
error group and
+     * two least-significant bytes for the error code.
+     *
+     * @return Full error code.
+     */
+    public int code() {
+        return code;
+    }
+
+    /**
+     * Returns error group.
+     *
+     * @see #code()
+     * @return Error group.
+     */
+    public int groupCode() {
+        return extractGroupCode(code);
+    }
+
+    /**
+     * Returns error code that uniquely identifies a problem within a group.
+     *
+     * @see #code()
+     * @see #groupCode()
+     * @return Error code.
+     */
+    public int errorCode() {
+        return extractErrorCode(code);
+    }
+
+    /**
+     * Returns an unique identifier of this exception.
+     *
+     * @return Unique identifier of this exception.
+     */
+    public UUID traceId() {
+        return traceId;
     }
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/lang/IgniteInternalException.java
 
b/modules/core/src/main/java/org/apache/ignite/lang/IgniteInternalException.java
index 4871418fb..70e5e4e5c 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/lang/IgniteInternalException.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/lang/IgniteInternalException.java
@@ -17,6 +17,14 @@
 
 package org.apache.ignite.lang;
 
+import static org.apache.ignite.lang.ErrorGroup.errorGroupByCode;
+import static org.apache.ignite.lang.ErrorGroup.errorMessage;
+import static org.apache.ignite.lang.ErrorGroup.errorMessageFromCause;
+import static org.apache.ignite.lang.ErrorGroup.extractErrorCode;
+import static org.apache.ignite.lang.ErrorGroup.extractGroupCode;
+import static org.apache.ignite.lang.ErrorGroups.Common.UNKNOWN_ERR;
+
+import java.util.UUID;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -26,11 +34,129 @@ public class IgniteInternalException extends 
RuntimeException {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
+    /** Name of the error group. */
+    private final String groupName;
+
+    /**
+     * Error code which contains information about error group and code, where 
code is unique within the group.
+     * The structure of a code is shown in the following diagram:
+     * +------------+--------------+
+     * |  16 bits   |    16 bits   |
+     * +------------+--------------+
+     * | Group Code |  Error Code  |
+     * +------------+--------------+
+     */
+    private final int code;
+
+    /** Unique identifier of this exception that should help locating the 
error message in a log file. */
+    private final UUID traceId;
+
+    /**
+     * Creates a new exception with the given error code.
+     *
+     * @param code Full error code.
+     */
+    public IgniteInternalException(int code) {
+        this(UUID.randomUUID(), code);
+    }
+
+    /**
+     * Creates a new exception with the given trace id and error code.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     */
+    public IgniteInternalException(UUID traceId, int code) {
+        super(errorMessage(traceId, code, null));
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code and detail message.
+     *
+     * @param code Full error code.
+     * @param message Detail message.
+     */
+    public IgniteInternalException(int code, String message) {
+        this(UUID.randomUUID(), code, message);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code and detail 
message.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Detail message.
+     */
+    public IgniteInternalException(UUID traceId, int code, String message) {
+        super(errorMessage(traceId, code, message));
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code and cause.
+     *
+     * @param code Full error code.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteInternalException(int code, Throwable cause) {
+        this(UUID.randomUUID(), code, cause);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code and cause.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteInternalException(UUID traceId, int code, Throwable cause) {
+        super(errorMessageFromCause(traceId, code, cause), cause);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
+    /**
+     * Creates a new exception with the given error code, detail message and 
cause.
+     *
+     * @param code Full error code.
+     * @param message Detail message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteInternalException(int code, String message, Throwable cause) {
+        this(UUID.randomUUID(), code, message, cause);
+    }
+
+    /**
+     * Creates a new exception with the given trace id, error code, detail 
message and cause.
+     *
+     * @param traceId Unique identifier of this exception.
+     * @param code Full error code.
+     * @param message Detail message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteInternalException(UUID traceId, int code, String message, 
Throwable cause) {
+        super(errorMessage(traceId, code, message), cause);
+
+        this.traceId = traceId;
+        this.groupName = errorGroupByCode((extractGroupCode(code))).name();
+        this.code = code;
+    }
+
     /**
      * Creates an empty exception.
      */
+    @Deprecated
     public IgniteInternalException() {
-        // No-op.
+        this(UNKNOWN_ERR);
     }
 
     /**
@@ -38,8 +164,9 @@ public class IgniteInternalException extends 
RuntimeException {
      *
      * @param msg Error message.
      */
+    @Deprecated
     public IgniteInternalException(String msg) {
-        super(msg);
+        this(UNKNOWN_ERR, msg);
     }
 
     /**
@@ -47,8 +174,9 @@ public class IgniteInternalException extends 
RuntimeException {
      *
      * @param cause Non-null throwable cause.
      */
+    @Deprecated
     public IgniteInternalException(Throwable cause) {
-        this(cause.getMessage(), cause);
+        this(UNKNOWN_ERR, cause);
     }
 
     /**
@@ -57,13 +185,60 @@ public class IgniteInternalException extends 
RuntimeException {
      * @param msg   Error message.
      * @param cause Optional nested exception (can be {@code null}).
      */
+    @Deprecated
     public IgniteInternalException(String msg, @Nullable Throwable cause) {
-        super(msg, cause);
+        this(UNKNOWN_ERR, msg, cause);
+    }
+
+    /**
+     * Returns a group name of this error.
+     *
+     * @see #groupCode()
+     * @see #code()
+     * @return Group name.
+     */
+    public String groupName() {
+        return groupName;
+    }
+
+    /**
+     * Returns a full error code which includes a group of the error and code 
which is uniquely identifies a problem within the group.
+     * This is a combination of two most-significant bytes that represent the 
error group and
+     * two least-significant bytes for the error code.
+     *
+     * @return Full error code.
+     */
+    public int code() {
+        return code;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return getClass() + ": " + getMessage();
+    /**
+     * Returns error group.
+     *
+     * @see #code()
+     * @return Error group.
+     */
+    public int groupCode() {
+        return extractGroupCode(code);
+    }
+
+    /**
+     * Returns error code that uniquely identifies a problem within a group.
+     *
+     * @see #code()
+     * @see #groupCode()
+     * @return Error code.
+     */
+    public int errorCode() {
+        return extractErrorCode(code);
+    }
+
+    /**
+     * Returns an unique identifier of this exception.
+     *
+     * @return Unique identifier of this exception.
+     */
+    public UUID traceId() {
+        return traceId;
     }
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/lang/IgniteStringFormatter.java 
b/modules/core/src/main/java/org/apache/ignite/lang/IgniteStringFormatter.java
index c65f28b6f..2aebdf325 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/lang/IgniteStringFormatter.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/lang/IgniteStringFormatter.java
@@ -67,7 +67,7 @@ public final class IgniteStringFormatter {
     /** Formatting anchor. */
     private static final String DELIM_STR = "{}";
 
-    /** Excape character. */
+    /** Escape character. */
     private static final char ESCAPE_CHAR = '\\';
 
     /**
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/causality/VersionedValueTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/causality/VersionedValueTest.java
index 14fac51c5..9880f5c1a 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/causality/VersionedValueTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/causality/VersionedValueTest.java
@@ -20,6 +20,8 @@ package org.apache.ignite.internal.causality;
 import static java.util.concurrent.CompletableFuture.completedFuture;
 import static java.util.concurrent.CompletableFuture.failedFuture;
 import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
@@ -362,8 +364,7 @@ public class VersionedValueTest {
 
         assertThrowsWithCause(() -> vv.get(0L).join(), 
IgniteInternalException.class);
 
-        assertEquals(exceptionMsg, exceptionRef.get().getMessage());
-        assertEquals(successfulCompletionsCount, 
actualSuccessfulCompletionsCount.get());
+        assertThat(exceptionRef.get().getMessage(), 
containsString(exceptionMsg));
     }
 
     /**
diff --git 
a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/BestEffortInstantiationTest.java
 
b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/BestEffortInstantiationTest.java
index 4dccead5c..474115b18 100644
--- 
a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/BestEffortInstantiationTest.java
+++ 
b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/BestEffortInstantiationTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.network.serialization.marshal;
 
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -92,6 +93,6 @@ class BestEffortInstantiationTest {
     @Test
     void whenNoDelegateSupportsThenInstantiationFails() {
         InstantiationException ex = assertThrows(InstantiationException.class, 
() -> instantiation.newInstance(Object.class));
-        assertThat(ex.getMessage(), is("No delegate supports " + 
Object.class));
+        assertThat(ex.getMessage(), containsString("No delegate supports " + 
Object.class));
     }
 }
diff --git 
a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultSchemaMismatchHandlerTest.java
 
b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultSchemaMismatchHandlerTest.java
index b12ce563d..6583c510f 100644
--- 
a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultSchemaMismatchHandlerTest.java
+++ 
b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultSchemaMismatchHandlerTest.java
@@ -18,7 +18,7 @@
 package org.apache.ignite.internal.network.serialization.marshal;
 
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -43,7 +43,7 @@ class DefaultSchemaMismatchHandlerTest {
     @Test
     void throwsOnFieldTypeChanged() {
         var ex = assertThrows(SchemaMismatchException.class, () -> 
handler.onFieldTypeChanged(new Object(), "field", int.class, "value"));
-        assertThat(ex.getMessage(), is("field type changed, serialized as int, 
value value of type java.lang.String"));
+        assertThat(ex.getMessage(), containsString("field type changed, 
serialized as int, value value of type java.lang.String"));
     }
 
     @Test
@@ -52,7 +52,8 @@ class DefaultSchemaMismatchHandlerTest {
                 () -> handler.onExternalizableIgnored(new Object(), 
mock(ObjectInput.class))
         );
         assertThat(ex.getMessage(),
-                is("Class java.lang.Object was serialized as an Externalizable 
remotely, but locally it is not an Externalizable")
+                containsString("Class java.lang.Object was serialized as an 
Externalizable remotely,"
+                        + " but locally it is not an Externalizable")
         );
     }
 
diff --git 
a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerCommonTest.java
 
b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerCommonTest.java
index a2254d7af..fb92cff2b 100644
--- 
a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerCommonTest.java
+++ 
b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerCommonTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.network.serialization.marshal;
 
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.notNullValue;
@@ -53,7 +54,7 @@ class DefaultUserObjectMarshallerCommonTest {
         byte[] tooManyBytes = Arrays.copyOf(marshalled.bytes(), 
marshalled.bytes().length + 1);
 
         UnmarshalException ex = assertThrows(UnmarshalException.class, () -> 
marshaller.unmarshal(tooManyBytes, descriptorRegistry));
-        assertThat(ex.getMessage(), is("After reading a value, 1 excessive 
byte(s) still remain"));
+        assertThat(ex.getMessage(), containsString("After reading a value, 1 
excessive byte(s) still remain"));
     }
 
     @Test
diff --git 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointMarkersStorageTest.java
 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointMarkersStorageTest.java
index 62adee532..8e65c3dc3 100644
--- 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointMarkersStorageTest.java
+++ 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointMarkersStorageTest.java
@@ -21,7 +21,7 @@ import static java.util.stream.Collectors.toSet;
 import static org.apache.ignite.internal.util.IgniteUtils.deleteIfExists;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.startsWith;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.io.FileWriter;
@@ -61,7 +61,7 @@ public class CheckpointMarkersStorageTest {
                 () -> new CheckpointMarkersStorage(testFile)
         );
 
-        assertThat(exception.getMessage(), startsWith("Could not create 
directory for checkpoint metadata"));
+        assertThat(exception.getMessage(), containsString("Could not create 
directory for checkpoint metadata"));
     }
 
     @Test
@@ -73,7 +73,7 @@ public class CheckpointMarkersStorageTest {
                 () -> new CheckpointMarkersStorage(workDir)
         );
 
-        assertThat(exception.getMessage(), startsWith("Not checkpoint markers 
found, they need to be removed manually"));
+        assertThat(exception.getMessage(), containsString("Not checkpoint 
markers found, they need to be removed manually"));
     }
 
     @Test
@@ -90,7 +90,7 @@ public class CheckpointMarkersStorageTest {
                 () -> new CheckpointMarkersStorage(workDir)
         );
 
-        assertThat(exception.getMessage(), startsWith("Not checkpoint markers 
found, they need to be removed manually"));
+        assertThat(exception.getMessage(), containsString("Not checkpoint 
markers found, they need to be removed manually"));
     }
 
     @Test
@@ -104,7 +104,7 @@ public class CheckpointMarkersStorageTest {
                 () -> new CheckpointMarkersStorage(workDir)
         );
 
-        assertThat(exception.getMessage(), startsWith("Found incomplete 
checkpoints"));
+        assertThat(exception.getMessage(), containsString("Found incomplete 
checkpoints"));
     }
 
     @Test
@@ -130,14 +130,14 @@ public class CheckpointMarkersStorageTest {
                 () -> markersStorage.onCheckpointBegin(UUID.randomUUID())
         );
 
-        assertThat(exception.getMessage(), startsWith("Could not create start 
checkpoint marker"));
+        assertThat(exception.getMessage(), containsString("Could not create 
start checkpoint marker"));
 
         exception = assertThrows(
                 IgniteInternalCheckedException.class,
                 () -> markersStorage.onCheckpointEnd(id0)
         );
 
-        assertThat(exception.getMessage(), startsWith("Could not create end 
checkpoint marker"));
+        assertThat(exception.getMessage(), containsString("Could not create 
end checkpoint marker"));
     }
 
     @Test
diff --git 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreFactoryTest.java
 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreFactoryTest.java
index 86b358c46..5a53ef27a 100644
--- 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreFactoryTest.java
+++ 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreFactoryTest.java
@@ -19,7 +19,7 @@ package 
org.apache.ignite.internal.pagememory.persistence.store;
 
 import static java.nio.ByteOrder.nativeOrder;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.startsWith;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -84,7 +84,7 @@ public class FilePageStoreFactoryTest {
                 () -> filePageStoreFactory.createPageStore(testFilePath)
         );
 
-        assertThat(exception.getMessage(), startsWith("Unknown version of file 
page store"));
+        assertThat(exception.getMessage(), containsString("Unknown version of 
file page store"));
     }
 
     private void checkCommonHeader(FilePageStore filePageStore) throws 
Exception {
diff --git 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManagerTest.java
 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManagerTest.java
index 74c46bdb0..316928781 100644
--- 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManagerTest.java
+++ 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManagerTest.java
@@ -20,9 +20,9 @@ package 
org.apache.ignite.internal.pagememory.persistence.store;
 import static java.util.stream.Collectors.toSet;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.emptyArray;
 import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.startsWith;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -75,7 +75,7 @@ public class FilePageStoreManagerTest {
 
         IgniteInternalCheckedException exception = 
assertThrows(IgniteInternalCheckedException.class, this::createManager);
 
-        assertThat(exception.getMessage(), startsWith("Could not create work 
directory for page stores"));
+        assertThat(exception.getMessage(), containsString("Could not create 
work directory for page stores"));
     }
 
     @Test
@@ -105,7 +105,7 @@ public class FilePageStoreManagerTest {
                     () -> manager.initialize("test", 0, 2)
             );
 
-            assertThat(exception.getMessage(), startsWith("Failed to 
initialize group working directory"));
+            assertThat(exception.getMessage(), containsString("Failed to 
initialize group working directory"));
 
             Files.delete(testGroupDir);
 
@@ -171,14 +171,14 @@ public class FilePageStoreManagerTest {
 
             assertThat(
                     exception.getMessage(),
-                    startsWith("Failed to get file page store for the given 
group ID (group has not been started)")
+                    containsString("Failed to get file page store for the 
given group ID (group has not been started)")
             );
 
             exception = assertThrows(IgniteInternalCheckedException.class, () 
-> manager.getStore(0, 2));
 
             assertThat(
                     exception.getMessage(),
-                    startsWith("Failed to get file page store for the given 
partition ID (partition has not been created)")
+                    containsString("Failed to get file page store for the 
given partition ID (partition has not been created)")
             );
         } finally {
             manager.stop();
diff --git 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/LongOperationAsyncExecutorTest.java
 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/LongOperationAsyncExecutorTest.java
index 946c4834f..90b99f09a 100644
--- 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/LongOperationAsyncExecutorTest.java
+++ 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/LongOperationAsyncExecutorTest.java
@@ -19,9 +19,8 @@ package 
org.apache.ignite.internal.pagememory.persistence.store;
 
 import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.runAsync;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.startsWith;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertSame;
@@ -55,7 +54,7 @@ public class LongOperationAsyncExecutorTest {
         Runnable task0 = () -> {
             assertNotSame(testMethodThread, Thread.currentThread());
 
-            assertThat(Thread.currentThread().getName(), 
startsWith("%test%async-op0-task-"));
+            assertThat(Thread.currentThread().getName(), 
containsString("%test%async-op0-task-"));
         };
 
         executor.async(createTask(task0, null, task0Future), "op0");
@@ -90,7 +89,7 @@ public class LongOperationAsyncExecutorTest {
             Runnable task1 = () -> {
                 assertNotSame(testMethodThread, Thread.currentThread());
 
-                assertThat(Thread.currentThread().getName(), 
startsWith("%test%async-op1-task-"));
+                assertThat(Thread.currentThread().getName(), 
containsString("%test%async-op1-task-"));
             };
 
             executor.async(createTask(task1, null, task1Future), "op1");
@@ -226,7 +225,7 @@ public class LongOperationAsyncExecutorTest {
 
             // Checks that the exception will be from task1.
             assertThat(exception.getCause(), 
instanceOf(IgniteInternalException.class));
-            assertThat(exception.getCause().getMessage(), 
equalTo("from_task_1"));
+            assertThat(exception.getCause().getMessage(), 
containsString("from_task_1"));
 
             assertThat(exception.getCause().getCause(), 
instanceOf(InterruptedException.class));
         } finally {
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/ClientSocketTests.cs 
b/modules/platforms/dotnet/Apache.Ignite.Tests/ClientSocketTests.cs
index f26ccc886..f6a0d09bb 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/ClientSocketTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/ClientSocketTests.cs
@@ -62,7 +62,7 @@ namespace Apache.Ignite.Tests
             var ex = Assert.ThrowsAsync<IgniteClientException>(
                 async () => await socket.DoOutInOpAsync((ClientOp)1234567, 
requestWriter));
 
-            Assert.AreEqual("Unexpected operation code: 1234567", ex!.Message);
+            StringAssert.Contains("Unexpected operation code: 1234567", 
ex!.Message);
         }
 
         [Test]
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Tests/Compute/ComputeTests.cs 
b/modules/platforms/dotnet/Apache.Ignite.Tests/Compute/ComputeTests.cs
index 1c0384c4f..872bc887e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/Compute/ComputeTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/Compute/ComputeTests.cs
@@ -136,7 +136,7 @@ namespace Apache.Ignite.Tests.Compute
             var ex = Assert.ThrowsAsync<IgniteClientException>(async () =>
                 await Client.Compute.ExecuteAsync<string>(await 
Client.GetClusterNodesAsync(), ErrorJob, "unused"));
 
-            Assert.AreEqual("class org.apache.ignite.tx.TransactionException: 
Custom job error", ex!.Message);
+            StringAssert.Contains("Custom job error", ex!.Message);
         }
 
         [Test]
@@ -147,7 +147,7 @@ namespace Apache.Ignite.Tests.Compute
             var ex = Assert.ThrowsAsync<IgniteClientException>(async () =>
                 await Client.Compute.ExecuteAsync<string>(new[] { unknownNode 
}, EchoJob, "unused"));
 
-            Assert.AreEqual("Specified node is not present in the cluster: y", 
ex!.Message);
+            StringAssert.Contains("Specified node is not present in the 
cluster: y", ex!.Message);
         }
 
         // TODO: Support all types (IGNITE-15431).
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Tests/Table/RecordViewBinaryTests.cs 
b/modules/platforms/dotnet/Apache.Ignite.Tests/Table/RecordViewBinaryTests.cs
index 5a3ad6662..4c863c016 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Tests/Table/RecordViewBinaryTests.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Tests/Table/RecordViewBinaryTests.cs
@@ -78,7 +78,7 @@ namespace Apache.Ignite.Tests.Table
         {
             var ex = Assert.ThrowsAsync<IgniteClientException>(async () => 
await TupleView.UpsertAsync(null, new IgniteTuple()));
 
-            Assert.AreEqual(
+            StringAssert.Contains(
                 "Missed key column: KEY",
                 ex!.Message);
         }
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Tests/Table/RecordViewPocoTests.cs 
b/modules/platforms/dotnet/Apache.Ignite.Tests/Table/RecordViewPocoTests.cs
index 0f12adaeb..cf59f074e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/Table/RecordViewPocoTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/Table/RecordViewPocoTests.cs
@@ -71,7 +71,7 @@ namespace Apache.Ignite.Tests.Table
 
             var ex = Assert.ThrowsAsync<IgniteClientException>(async () => 
await pocoView.UpsertAsync(null, new object()));
 
-            Assert.AreEqual("Missed key column: KEY", ex!.Message);
+            StringAssert.Contains("Missed key column: KEY", ex!.Message);
         }
 
         [Test]
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientComputeTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientComputeTest.java
index e5f6c823e..0d0c4b70f 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientComputeTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientComputeTest.java
@@ -135,7 +135,7 @@ public class ItThinClientComputeTest extends 
ItAbstractThinClientTest {
 
         IgniteClientException cause = (IgniteClientException) ex.getCause();
 
-        assertThat(cause.getMessage(), containsString("TransactionException: 
Custom job error"));
+        assertThat(cause.getMessage(), containsString("Custom job error"));
     }
 
     @ParameterizedTest
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientTransactionsTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientTransactionsTest.java
index 6fc6056b7..c9783a281 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientTransactionsTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientTransactionsTest.java
@@ -19,7 +19,6 @@ package org.apache.ignite.internal.runner.app.client;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.startsWith;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -202,7 +201,7 @@ public class ItThinClientTransactionsTest extends 
ItAbstractThinClientTest {
         tx.commit();
 
         TransactionException ex = assertThrows(TransactionException.class, 
tx::rollback);
-        assertEquals("Transaction is already committed.", ex.getMessage());
+        assertThat(ex.getMessage(), containsString("Transaction is already 
committed"));
     }
 
     @Test
@@ -211,7 +210,7 @@ public class ItThinClientTransactionsTest extends 
ItAbstractThinClientTest {
         tx.rollback();
 
         TransactionException ex = assertThrows(TransactionException.class, 
tx::commit);
-        assertEquals("Transaction is already rolled back.", ex.getMessage());
+        assertThat(ex.getMessage(), containsString("Transaction is already 
rolled back"));
     }
 
     @Test
@@ -241,7 +240,7 @@ public class ItThinClientTransactionsTest extends 
ItAbstractThinClientTest {
         String expected = "Unsupported transaction implementation: "
                 + "'class 
org.apache.ignite.internal.runner.app.client.ItThinClientTransactionsTest";
 
-        assertThat(ex.getMessage(), startsWith(expected));
+        assertThat(ex.getMessage(), containsString(expected));
     }
 
     @Test
@@ -253,7 +252,7 @@ public class ItThinClientTransactionsTest extends 
ItAbstractThinClientTest {
 
             IgniteClientException ex = 
assertThrows(IgniteClientException.class, () -> recordView.upsert(tx, 
Tuple.create()));
 
-            assertEquals("Transaction context has been lost due to connection 
errors.", ex.getMessage());
+            assertThat(ex.getMessage(), containsString("Transaction context 
has been lost due to connection errors"));
         }
     }
 
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java
index 7c43644c0..d524832a8 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java
@@ -23,6 +23,7 @@ import static 
org.apache.ignite.internal.storage.rocksdb.RocksDbStorageEngine.EN
 import static 
org.apache.ignite.internal.storage.rocksdb.configuration.schema.RocksDbStorageEngineConfigurationSchema.DEFAULT_DATA_REGION_NAME;
 import static org.apache.ignite.internal.testframework.IgniteTestUtils.await;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.startsWith;
@@ -572,7 +573,7 @@ public class MockedStructuresTest extends 
IgniteAbstractTest {
                 ))
         );
 
-        assertThat(exception.getMessage(), startsWith("Unsuspected table 
option type"));
+        assertThat(exception.getMessage(), containsString("Unsuspected table 
option type"));
 
         exception = assertThrows(
                 IgniteException.class,
@@ -582,7 +583,7 @@ public class MockedStructuresTest extends 
IgniteAbstractTest {
                 ))
         );
 
-        assertThat(exception.getMessage(), startsWith("Unexpected table 
option"));
+        assertThat(exception.getMessage(), containsString("Unexpected table 
option"));
 
         exception = assertThrows(
                 IgniteException.class,
@@ -592,7 +593,7 @@ public class MockedStructuresTest extends 
IgniteAbstractTest {
                 ))
         );
 
-        assertThat(exception.getMessage(), startsWith("Table option validation 
failed"));
+        assertThat(exception.getMessage(), containsString("Table option 
validation failed"));
     }
 
     @Test

Reply via email to