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:

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

abstract type IncompleteStrategy <: CTSolvers.Strategies.AbstractStrategy end
julia> CTSolvers.Strategies.id(IncompleteStrategy)ERROR: Control Toolbox Error

❌ Error: CTBase.Exceptions.NotImplemented, Strategy ID method not implemented
🔧 Required method: id(::Type{<:Main.IncompleteStrategy})
📂 Context: AbstractStrategy.id - required method implementation
💡 Suggestion: Implement id(::Type{<:Main.IncompleteStrategy}) to return a unique Symbol identifier

Fix: Implement the missing method:

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

Strategy contract — missing metadata

julia> CTSolvers.Strategies.metadata(IncompleteStrategy)ERROR: Control Toolbox Error

❌ Error: CTBase.Exceptions.NotImplemented, Strategy metadata method not implemented
🔧 Required method: metadata(::Type{<:Main.IncompleteStrategy})
📂 Context: AbstractStrategy.metadata - required method implementation
💡 Suggestion: Implement metadata(::Type{<:Main.IncompleteStrategy}) to return StrategyMetadata with OptionDefinitions

Optimization problem contract — missing builder

struct MinimalProblem <: CTSolvers.Optimization.AbstractOptimizationProblem end
julia> CTSolvers.Optimization.get_adnlp_model_builder(MinimalProblem())ERROR: Control Toolbox Error

❌ Error: CTBase.Exceptions.NotImplemented, ADNLP model builder not implemented
🔧 Required method: get_adnlp_model_builder(prob::Main.MinimalProblem)
📂 Context: AbstractOptimizationProblem.get_adnlp_model_builder - required method implementation
💡 Suggestion: Implement get_adnlp_model_builder for Main.MinimalProblem to support ADNLPModels backend
julia> CTSolvers.Optimization.get_exa_model_builder(MinimalProblem())ERROR: Control Toolbox Error

❌ Error: CTBase.Exceptions.NotImplemented, ExaModel builder not implemented
🔧 Required method: get_exa_model_builder(prob::Main.MinimalProblem)
📂 Context: AbstractOptimizationProblem.get_exa_model_builder - required method implementation
💡 Suggestion: Implement get_exa_model_builder for Main.MinimalProblem to support ExaModels backend

Where it's thrown

MethodContext
Strategies.id(::Type{T})Strategy type missing id
Strategies.metadata(::Type{T})Strategy type missing metadata
Strategies.options(strategy)Strategy instance has no options field and no custom getter
get_adnlp_model_builder(prob)Problem doesn't support ADNLPModels
get_exa_model_builder(prob)Problem doesn't support ExaModels
get_adnlp_solution_builder(prob)Problem doesn't support ADNLP solutions
get_exa_solution_builder(prob)Problem doesn't support Exa solutions

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 = CTSolvers.Options.OptionDefinition(
           name = :max_iter, type = Integer, default = 100,
           description = "Maximum iterations",
       )max_iter :: Integer (default: 100)
julia> CTSolvers.Options.extract_option((max_iter = "hello",), def)ERROR: Control Toolbox Error ❌ Error: CTBase.Exceptions.IncorrectArgument, Invalid option type 🔍 Got: value hello of type String, Expected: Integer 📂 Context: Option extraction for max_iter 💡 Suggestion: 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:

bad_def = CTSolvers.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> CTSolvers.Options.extract_option((tol = -1.0,), bad_def)┌ Error: Validation failed for option tol with value -1.0
│   exception =
│    Control Toolbox Error
│    
│    ❌ Error: CTBase.Exceptions.IncorrectArgument, Invalid tolerance value
│    🔍 Got: tol=-1.0, Expected: positive real number (> 0)
│    📂 Context: tol validation
│    💡 Suggestion: Provide a positive tolerance value (e.g., 1e-6, 1e-8)
│    📍 In your code:
│         #2 at error_messages.md:108
│         └── extract_option at extraction.jl:70
│             └── top-level scope at REPL[1]:1
│    
│    Stacktrace:
│      [1] (::Main.var"#2#3")(x::Float64)
│        @ Main ./error_messages.md:108
│      [2] extract_option(kwargs::@NamedTuple{tol::Float64}, def::CTSolvers.Options.OptionDefinition{Float64})
│        @ CTSolvers.Options ~/work/CTSolvers.jl/CTSolvers.jl/src/Options/extraction.jl:70
│      [3] top-level scope
│        @ REPL[1]:1
│      [4] eval(m::Module, e::Any)
│        @ Core ./boot.jl:489
│      [5] #67
│        @ ~/.julia/packages/Documenter/AXNMp/src/expander_pipeline.jl:978 [inlined]
│      [6] cd(f::Documenter.var"#67#68"{Module}, dir::String)
│        @ Base.Filesystem ./file.jl:112
│      [7] (::Documenter.var"#65#66"{Documenter.Page, Module})()
│        @ Documenter ~/.julia/packages/Documenter/AXNMp/src/expander_pipeline.jl:977
│      [8] (::IOCapture.var"#12#13"{Type{InterruptException}, Documenter.var"#65#66"{Documenter.Page, Module}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, Base.PipeEndpoint, Base.PipeEndpoint})()
│        @ IOCapture ~/.julia/packages/IOCapture/MR051/src/IOCapture.jl:170
│      [9] with_logstate(f::IOCapture.var"#12#13"{Type{InterruptException}, Documenter.var"#65#66"{Documenter.Page, Module}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, Base.PipeEndpoint, Base.PipeEndpoint}, logstate::Base.CoreLogging.LogState)
│        @ Base.CoreLogging ./logging/logging.jl:542
│     [10] with_logger(f::Function, logger::Base.CoreLogging.ConsoleLogger)
│        @ Base.CoreLogging ./logging/logging.jl:653
│     [11] capture(f::Documenter.var"#65#66"{Documenter.Page, Module}; rethrow::Type, color::Bool, passthrough::Bool, capture_buffer::IOBuffer, io_context::Vector{Any})
│        @ IOCapture ~/.julia/packages/IOCapture/MR051/src/IOCapture.jl:167
│     [12] runner(::Type{Documenter.Expanders.REPLBlocks}, node::MarkdownAST.Node{Nothing}, page::Documenter.Page, doc::Documenter.Document)
│        @ Documenter ~/.julia/packages/Documenter/AXNMp/src/expander_pipeline.jl:976
│     [13] dispatch(::Type{Documenter.Expanders.ExpanderPipeline}, ::MarkdownAST.Node{Nothing}, ::Vararg{Any})
│        @ Documenter.Selectors ~/.julia/packages/Documenter/AXNMp/src/utilities/Selectors.jl:170
│     [14] expand(doc::Documenter.Document)
│        @ Documenter ~/.julia/packages/Documenter/AXNMp/src/expander_pipeline.jl:60
│     [15] runner(::Type{Documenter.Builder.ExpandTemplates}, doc::Documenter.Document)
│        @ Documenter ~/.julia/packages/Documenter/AXNMp/src/builder_pipeline.jl:224
│     [16] dispatch(::Type{Documenter.Builder.DocumentPipeline}, x::Documenter.Document)
│        @ Documenter.Selectors ~/.julia/packages/Documenter/AXNMp/src/utilities/Selectors.jl:170
│     [17] #95
│        @ ~/.julia/packages/Documenter/AXNMp/src/makedocs.jl:283 [inlined]
│     [18] withenv(::Documenter.var"#95#96"{Documenter.Document}, ::Pair{String, Nothing}, ::Vararg{Pair{String, Nothing}})
│        @ Base ./env.jl:265
│     [19] #93
│        @ ~/.julia/packages/Documenter/AXNMp/src/makedocs.jl:282 [inlined]
│     [20] cd(f::Documenter.var"#93#94"{Documenter.Document}, dir::String)
│        @ Base.Filesystem ./file.jl:112
│     [21] makedocs(; debug::Bool, format::Documenter.HTMLWriter.HTML, kwargs::@Kwargs{draft::Bool, remotes::Nothing, warnonly::Bool, sitename::String, pages::Vector{Pair{String, Any}}})
│        @ Documenter ~/.julia/packages/Documenter/AXNMp/src/makedocs.jl:281
│     [22] (::var"#4#5")(api_pages::Vector{Pair{String, Vector{Pair{String, String}}}})
│        @ Main ~/work/CTSolvers.jl/CTSolvers.jl/docs/make.jl:36
│     [23] with_api_reference(f::var"#4#5", src_dir::String, ext_dir::String)
│        @ Main ~/work/CTSolvers.jl/CTSolvers.jl/docs/api_reference.jl:304
│     [24] top-level scope
│        @ ~/work/CTSolvers.jl/CTSolvers.jl/docs/make.jl:35
│     [25] include(mapexpr::Function, mod::Module, _path::String)
│        @ Base ./Base.jl:307
│     [26] top-level scope
│        @ none:1
│     [27] eval(m::Module, e::Any)
│        @ Core ./boot.jl:489
│     [28] exec_options(opts::Base.JLOptions)
│        @ Base ./client.jl:283
│     [29] _start()
│        @ Base ./client.jl:550
└ @ CTSolvers.Options ~/work/CTSolvers.jl/CTSolvers.jl/src/Options/extraction.jl:72
ERROR: Control Toolbox Error

❌ Error: CTBase.Exceptions.IncorrectArgument, Invalid tolerance value
🔍 Got: tol=-1.0, Expected: positive real number (> 0)
📂 Context: tol validation
💡 Suggestion: 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> CTSolvers.Options.OptionDefinition(
           name = :count, type = Integer, default = "hello",
           description = "A count",
       )ERROR: Control Toolbox Error

❌ Error: CTBase.Exceptions.IncorrectArgument, Type mismatch in option definition
🔍 Got: default value hello of type String, Expected: value of type Integer
📂 Context: OptionDefinition constructor - validating type compatibility
💡 Suggestion: 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> CTSolvers.Options.OptionValue(42, :invalid_source)ERROR: Control Toolbox Error

❌ Error: CTBase.Exceptions.IncorrectArgument, Invalid option source
🔍 Got: source=invalid_source, Expected: :default, :user, or :computed
📂 Context: OptionValue constructor - validating source provenance
💡 Suggestion: 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.Ipopt()ERROR: Control Toolbox Error

❌ Error: CTBase.Exceptions.ExtensionError, missing dependencies to create Ipopt, access options, and solve problems
📦 Missing dependencies: NLPModelsIpopt
💡 Suggestion: julia> using NLPModelsIpopt

Fix: Load the required package before using the solver:

using NLPModelsIpopt  # loads the CTSolversIpopt extension
solver = Solvers.Ipopt(max_iter = 1000)

Where it's thrown

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

Display Examples

OptionDefinition display

CTSolvers.Options.OptionDefinition(
    name = :max_iter, type = Integer, default = 1000,
    description = "Maximum number of iterations",
    aliases = (:maxiter,),
)
max_iter (maxiter) :: Integer (default: 1000)

OptionValue display

CTSolvers.Options.OptionValue(1000, :user)
1000 (user)
CTSolvers.Options.OptionValue(1e-8, :default)
1.0e-8 (default)

NotProvided display

CTSolvers.Options.NotProvided
NotProvided

Option extraction — successful

def = CTSolvers.Options.OptionDefinition(
    name = :grid_size, type = Int, default = 100,
    description = "Grid size", aliases = (:n,),
)
opt_value, remaining = CTSolvers.Options.extract_option((n = 200, tol = 1e-6), def)
println("Extracted: ", opt_value)
println("Remaining: ", remaining)
Extracted: 200 (user)
Remaining: (tol = 1.0e-6,)

Multiple option extraction

defs = [
    CTSolvers.Options.OptionDefinition(
        name = :grid_size, type = Int, default = 100, description = "Grid size",
    ),
    CTSolvers.Options.OptionDefinition(
        name = :tol, type = Float64, default = 1e-6, description = "Tolerance",
    ),
]
extracted, remaining = CTSolvers.Options.extract_options((grid_size = 200, max_iter = 1000), defs)
println("Extracted: ", extracted)
println("Remaining: ", remaining)
Extracted: Dict{Symbol, CTSolvers.Options.OptionValue}(:grid_size => 200 (user), :tol => 1.0e-6 (default))
Remaining: (max_iter = 1000,)

Best Practices for Error Messages

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

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