Skip to content

Error Messages Reference

This page catalogues all exception types used in CTSolvers, with live examples and recommended fixes. CTSolvers uses enriched exceptions from CTBase.Exceptions that carry structured fields (got, expected, suggestion, context) for actionable error messages.

Exception Types

CTSolvers uses three exception types from CTBase.Exceptions:

TypePurpose
NotImplementedContract method not implemented by a concrete type
IncorrectArgumentInvalid argument value, type, or routing
ExtensionErrorRequired package extension not loaded

All three accept keyword arguments for structured messages:

julia
using CTSolvers
using CTBase: CTBase
const Exceptions = CTBase.Exceptions

NotImplemented — Contract Not Implemented

Thrown when a concrete type doesn't implement a required contract method.

Strategy contract — missing id

julia
abstract type IncompleteStrategy <: CTBase.Strategies.AbstractStrategy end
julia
julia> CTBase.Strategies.id(IncompleteStrategy)
NotImplemented  top-level scope, REPL[1]:2

│  Strategy ID method not implemented

│  Method   id(::Type{<:Main.IncompleteStrategy})

│  Context  AbstractStrategy.id - required method implementation
│  Hint     Implement id(::Type{<:Main.IncompleteStrategy}) to return a unique Symbol identifier
└─

Fix: Implement the missing method:

julia
CTBase.Strategies.id(::Type{<:IncompleteStrategy}) = :my_strategy

Strategy contract — missing metadata

julia
julia> CTBase.Strategies.metadata(IncompleteStrategy)
NotImplemented  top-level scope, REPL[1]:2

│  Strategy metadata method not implemented

│  Method   metadata(::Type{<:Main.IncompleteStrategy})

│  Context  AbstractStrategy.metadata - required method implementation
│  Hint     Implement metadata(::Type{<:Main.IncompleteStrategy}) to return StrategyMetadata with OptionDefinitions
└─

Optimization problem contract — missing build_model

Define a problem type and a modeler, but no (problem, modeler) method. A dedicated block label (optprob) keeps these throwaway types out of the shared errors scope:

julia
using CTSolvers
struct MinimalProblem <: CTSolvers.Optimization.AbstractOptimizationProblem end
struct MinimalModeler <: CTSolvers.Modelers.AbstractNLPModeler end

The generic stub in Modelers/contract.jl throws NotImplemented as soon as build_model is called with a (problem, modeler) pair for which no concrete method exists:

julia
julia> CTSolvers.Optimization.build_model(MinimalProblem(), nothing, MinimalModeler())
NotImplemented  build_model, contract.jl:46

│  Model building not implemented

│  Method   Optimization.build_model(prob::Main.MinimalProblem, initial_guess, modeler::Main.MinimalModeler)

│  Context  Modelers.build_model - required method implementation
│  Hint     Implement build_model for this (problem, modeler) pair in the package providing the problem
└─

Fix: Implement build_model and build_solution in the package providing the problem, dispatching on the concrete (problem, modeler) pair (see Implementing an Optimization Problem).

Where it's thrown

MethodContext
CTBase.Strategies.id(::Type{T})Strategy type missing id
CTBase.Strategies.metadata(::Type{T})Strategy type missing metadata
CTBase.Strategies.options(strategy)Strategy instance has no options field and no custom getter
Optimization.build_model(prob, init, modeler)No concrete method for this (problem, modeler) pair
Optimization.build_solution(built, stats, modeler)No concrete method for this (built, modeler) pair

IncorrectArgument — Invalid Arguments

Thrown for invalid values, types, or routing errors. This is the most common exception in CTSolvers.

Type mismatch in extraction

When extract_option receives a value of the wrong type:

julia> def = CTBase.Options.OptionDefinition(
           name = :max_iter, type = Integer, default = 100,
           description = "Maximum iterations",
       )
max_iter::Integer (default: 100)

julia> CTBase.Options.extract_option((max_iter = "hello",), def)
IncorrectArgument → top-level scope, REPL[2]:2

│  Invalid option type

│  Got       value hello of type String
│  Expected  Integer

│  Context   Option extraction for max_iter
│  Hint      Ensure the option value matches the expected type
└─

Fix: Provide a value of the correct type.

Validator failure

When a value doesn't satisfy the validator constraint:

julia
bad_def = CTBase.Options.OptionDefinition(
    name = :tol, type = Real, default = 1e-8,
    description = "Tolerance",
    validator = x -> x > 0 || throw(Exceptions.IncorrectArgument(
        "Invalid tolerance value",
        got = "tol=$x",
        expected = "positive real number (> 0)",
        suggestion = "Provide a positive tolerance value (e.g., 1e-6, 1e-8)",
        context = "tol validation",
    )),
)
julia
julia> CTBase.Options.extract_option((tol = -1.0,), bad_def)
IncorrectArgument  #2, error_messages.md:130

│  Invalid tolerance value

│  Got       tol=-1.0
│  Expected  positive real number (> 0)

│  Context   tol validation
│  Hint      Provide a positive tolerance value (e.g., 1e-6, 1e-8)
└─

Fix: Provide a value that satisfies the validator constraint.

Type mismatch in OptionDefinition constructor

When the default value doesn't match the declared type:

julia
julia> CTBase.Options.OptionDefinition(
           name = :count, type = Integer, default = "hello",
           description = "A count",
       )
IncorrectArgument  top-level scope, REPL[1]:2

│  Type mismatch in option definition

│  Got       default value hello of type String
│  Expected  value of type Integer

│  Context   OptionDefinition constructor - validating type compatibility
│  Hint      Ensure the default value matches the declared type, or adjust the type parameter
└─

Fix: Ensure the default value matches the declared type.

Invalid OptionValue source

julia
julia> CTBase.Options.OptionValue(42, :invalid_source)
IncorrectArgument  top-level scope, REPL[1]:2

│  Invalid option source

│  Got       source=invalid_source
│  Expected  :default, :user, or :computed

│  Context   OptionValue constructor - validating source provenance
│  Hint      Use one of the valid source symbols: :default (tool default), :user (user-provided), or :computed (derived)
└─

Fix: Use :default, :user, or :computed.

ExtensionError — Extension Not Loaded

Thrown when a solver requires a package extension that hasn't been loaded.

julia> CTSolvers.Solvers.MadNLP()
MadNLP{CPU} (instance, id=:madnlp)
├─ max_iter = 1000  [default]
├─ tol = 1.0e-8  [default]
├─ linear_solver = MumpsSolver  [computed]
└─ print_level = INFO  [default]
Tip: use describe(MadNLP) to see all available options.

Fix: Load the required package before using the solver:

julia
using MadNLP  # loads the CTSolversMadNLP extension
solver = Solvers.MadNLP(max_iter = 1000)

Where it's thrown

SolverRequired package
Solvers.IpoptNLPModelsIpopt
Solvers.MadNLPMadNLP
Solvers.KnitroKNITRO
Solvers.MadNCLMadNCL

Best Practices for Error Messages

When implementing new validators or error paths, follow the CTSolvers convention:

julia
throw(Exceptions.IncorrectArgument(
    "Short, clear description of the problem",
    got        = "what the user actually provided",
    expected   = "what was expected instead",
    suggestion = "actionable fix the user can apply",
    context    = "ModuleName.function_name - specific validation step",
))
  • got: Show the actual value, including its type if relevant

  • expected: Be specific about valid values or ranges

  • suggestion: Provide a concrete example the user can copy

  • context: Include the module and function name for traceability