Exceptions
Every exception thrown by the provider derives from NTiException, which derives from DbException as the ADO.NET contract requires: a generic catch (DbException) therefore catches everything NTi (DbException reference).
DbException
NTiException base of every NTi exception
NTiSqlException SQL error from the database server (negative SQLCODE)
NTiCommandException CL command or program call failure
NTiCommunicationException communication failure, broken connectionWhich condition throws what
| Exception | Thrown when | Specific properties |
|---|---|---|
NTiException |
a provider error outside the three derived categories: API misuse, impossible conversion (for example requesting text in CCSID 65535), a failing MFA callback (original cause preserved as InnerException) |
those of DbException |
NTiSqlException |
the database server returns a negative SQLCODE | SqlCode; SqlState (5 character SQLSTATE); SecondLevelMessage (second level text when requested) |
NTiCommandException |
a CL command, a program call or a service program call fails | ReturnCode (command server return code); Messages (IBM i message stack, see below) |
NTiCommunicationException |
connection failure, timeout, unexpected end of stream, malformed frame, TLS error | IsTransient, always true: the faulty connection is broken and discarded, a new attempt on a fresh connection may succeed (EF/Polly retry strategies) |
On net6 and later, SqlState overrides DbException.SqlState: generic code such as catch (DbException e) when (e.SqlState == "42704") works as is.
NTiCommandResult: the message stack
NTiCommandException.Messages carries the IBM i message stack (CPFxxxx, MCHxxxx...) returned by the command server; each entry is an NTiCommandResult:
| Property | Content |
|---|---|
Id |
message identifier (CPF2105, MCH0602, SQL0204...) |
Type |
message type code |
Severity |
severity, 0 to 99 |
File |
message file |
Library |
message file library |
Text |
first level text |
SubstitutionData |
substitution data of the message |
Help |
second level (help) text |
The same stack is available on the success side through connection.Result (see NTiConnection).
ToString and StackTrace: no call stack
Across the whole hierarchy, StackTrace is empty and ToString() is rendered WITHOUT a call stack: the shipped product is obfuscated and call stacks are not part of the diagnostic surface (v4 policy). The actionable information is the message and the chain of inner causes (InnerException), always preserved.
Cancellation: the connection breaks by contract
Cancelling the token of an in-flight operation throws OperationCanceledException carrying the CALLER's token (not an NTi exception) and breaks the connection BY CONTRACT: the in-flight frame is lost, the connection is never reused nor returned to the pool. Reopen the connection (or take a fresh one from the pool) before continuing.
using System;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using Aumerial.Data.Nti;
class ExceptionDemo
{
static async Task Main()
{
await using var connection = new NTiConnection("server=MYIBMI;user=MYUSER;password=MYPASSWORD");
await connection.OpenAsync();
try
{
await connection.ExecuteClCommandAsync("DLTLIB LIB(NOPE)");
}
catch (NTiCommandException e) // CL or program failure
{
Console.WriteLine($"Return code {e.ReturnCode}");
foreach (var m in e.Messages) // IBM i message stack
Console.WriteLine($"{m.Id} [{m.Severity}] {m.Text}");
}
try
{
using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM MYLIB.NOPE";
await using var reader = await command.ExecuteReaderAsync();
}
catch (NTiSqlException e) // SQL error: negative SQLCODE
{
Console.WriteLine($"SQLCODE {e.SqlCode}, SQLSTATE {e.SqlState}");
Console.WriteLine(e.SecondLevelMessage);
}
catch (DbException e) // generic net: everything NTi derives from DbException
{
Console.WriteLine(e.Message); // ToString() and Message are rendered without a stack
}
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
using var slow = connection.CreateCommand();
slow.CommandText = "CALL MYLIB.LONGPROC()";
await slow.ExecuteNonQueryAsync(cts.Token);
}
catch (OperationCanceledException) // cancellation: connection broken by contract
{
// The in-flight frame is lost: reopen the connection before continuing.
}
}
}