Table of Contents

Errors

OCCT reports failure two ways: exceptions (Standard_Failure and its subclasses) for invalid input, and status flags (IsDone(), Error(), HasErrors()) on algorithms that can fail on valid input.

Exceptions

C++ exceptions never cross into .NET on their own. Every wrapper catches them and NetOcc throws an OcctException when the call returns:

sequenceDiagram
    participant App as your code
    participant Proxy as C# proxy
    participant Wrapper as native wrapper
    participant OCCT
    App->>Proxy: new gp_Dir(0, 0, 0)
    Proxy->>Wrapper: P/Invoke
    Wrapper->>OCCT: gp_Dir(0, 0, 0)
    OCCT-->>Wrapper: throw Standard_ConstructionError
    Wrapper-->>Proxy: type and message, via a callback
    Proxy-->>App: throw OcctException
try
{
  var flat = new BRepPrimAPI_MakeBox(0, 10, 10).Shape();
}
catch (OcctException e) when (e.Is<Standard_DomainError>())
{
  // OcctType names the class OCCT threw, OcctMessage has its message
  caught = $"{e.OcctType}: {e.OcctMessage}";
}
Member Gives
OcctType the class OCCT threw: Standard_ConstructionError, or std::exception for the standard library's
OcctMessage OCCT's message, if it gave one
Is<T>() whether it's a T or a subclass, by OCCT's class hierarchy

Is<T> follows the hierarchy, so catching a base class catches its subclasses:

try
{
  var zero = new gp_Dir(0, 0, 0);
}
catch (OcctException e)
{
  type = e.OcctType;                                 // "Standard_ConstructionError"
  construction = e.Is<Standard_ConstructionError>(); // true
  domain = e.Is<Standard_DomainError>();             // true: its base class
  range = e.Is<Standard_RangeError>();               // false
}
flowchart LR
    failure[Standard_Failure] --- domain[Standard_DomainError]
    failure --- numeric[Standard_NumericError]
    failure --- program[Standard_ProgramError]
    failure --- notDone[StdFail_NotDone]
    domain --- construction[Standard_ConstructionError]
    domain --- nullObject[Standard_NullObject]
    domain --- noSuchObject[Standard_NoSuchObject]
    domain --- typeMismatch[Standard_TypeMismatch]
    domain --- dimension[Standard_DimensionError]
    domain --- range[Standard_RangeError]
    range --- outOfRange[Standard_OutOfRange]
    range --- negative[Standard_NegativeValue]
    range --- nullValue[Standard_NullValue]
    numeric --- divide[Standard_DivideByZero]
    numeric --- overflow[Standard_Overflow]
    program --- notImplemented[Standard_NotImplemented]
Thrown for Usually
Standard_ConstructionError a degenerate input: a zero vector as a direction, coincident points
Standard_DomainError an argument outside what the method accepts: a zero-size box
Standard_OutOfRange an index outside a collection's bounds
Standard_TypeMismatch a wrong cast: TopoDS.Face of an edge
Standard_NoSuchObject a key a map doesn't have
StdFail_NotDone the result of an algorithm that failed

Builders that fail

Builders check their input and record why they failed, without throwing:

// builders check their input and say why they failed, without throwing
var point = new gp_Pnt(1, 1, 1);
var edge = new BRepBuilderAPI_MakeEdge(point, point);
var done = edge.IsDone(); // false
var why = edge.Error();   // BRepBuilderAPI_LineThroughIdenticPoints

// asking a failed builder for its result throws StdFail_NotDone
Action result = () => edge.Edge();
Builder Why it failed
BRepBuilderAPI_MakeEdge Error(): BRepBuilderAPI_EdgeError
BRepBuilderAPI_MakeWire Error(): BRepBuilderAPI_WireError, e.g. disconnected edges
BRepBuilderAPI_MakeFace Error(): BRepBuilderAPI_FaceError, e.g. a non-planar wire
BRepFilletAPI_MakeFillet NbFaultyContours(), StripeStatus(i)
BRepAlgoAPI_* HasErrors(), HasWarnings(), GetReport()

Where failure is possible on valid input, as with fillets whose radius doesn't fit, check before asking for the result:

// a radius the box can't take
var fillet = new BRepFilletAPI_MakeFillet(box);
fillet.Add(20, edge);
fillet.Build();

TopoDS_Shape result = fillet.IsDone() ? fillet.Shape() : box; // keep the box unrounded

Booleans report through a message report instead:

// booleans report through HasErrors and HasWarnings
var cut = new BRepAlgoAPI_Cut(box, new TopoDS_Shape()); // a null tool
var failed = cut.HasErrors();                           // true

What isn't checked

OCCT doesn't check everything, and a C++ crash ends the process: it can't be caught.

Warning

A null shape has no type: new TopoDS_Shape().ShapeType() crashes, as it does in C++, where it dereferences a null handle (exploring it, Location() and NbChildren() are safe). Check IsNull() on shapes an algorithm may leave empty, and null returns such as BRep_Tool.Triangulation of a face without a mesh.

NetOcc checks what it adds: its collection indexers, array lengths for fixed-size parameters, and size_t values on x86 throw OcctException rather than read out of bounds.