Error Handling

Handle SolverForgeError types and troubleshoot common issues

SolverForge uses the SolverForgeError enum for all error types.

SolverForgeError

use solverforge_core::{SolverForgeError, SolverForgeResult};

fn solve_problem() -> SolverForgeResult<String> {
    // ... operations that may fail
    Ok("solution".to_string())
}

match solve_problem() {
    Ok(solution) => println!("Success: {}", solution),
    Err(e) => eprintln!("Error: {}", e),
}

Error Variants

Serialization

JSON serialization/deserialization errors:

SolverForgeError::Serialization(String)

Common causes:

  • Invalid JSON in problem data
  • Malformed score strings
  • Type mismatches

Example:

let score = HardSoftScore::parse("invalid")?;
// Error: Serialization error: Invalid HardSoftScore format...

Http

HTTP communication errors with the solver service:

SolverForgeError::Http(String)

Common causes:

  • Service not running
  • Network timeout
  • Connection refused

Solver

Errors returned by the solver service:

SolverForgeError::Solver(String)

Common causes:

  • Invalid constraint configuration
  • WASM execution failure
  • Memory allocation failure

WasmGeneration

Errors during WASM module generation:

SolverForgeError::WasmGeneration(String)

Common causes:

  • Invalid expression tree
  • Unknown field access
  • Missing domain model

Bridge

Language binding bridge errors:

SolverForgeError::Bridge(String)

Common causes:

  • Handle invalidation
  • Type conversion failures

Validation

Domain model validation errors:

SolverForgeError::Validation(String)

Common causes:

  • Missing @PlanningSolution class
  • No @PlanningEntity classes
  • Missing @PlanningVariable on entities
  • Missing @PlanningScore field

Example:

let model = DomainModel::builder()
    .add_class(DomainClass::new("Shift"))  // No annotations!
    .build_validated()?;
// Error: Validation error: No @PlanningSolution class found

Configuration

Configuration errors:

SolverForgeError::Configuration(String)

Common causes:

  • Invalid termination config
  • Invalid environment mode

Service

Embedded service lifecycle errors:

SolverForgeError::Service(String)

Common causes:

  • Java not found
  • Service startup timeout
  • Port already in use

Io

Standard I/O errors:

SolverForgeError::Io(std::io::Error)

Common causes:

  • File not found
  • Permission denied

Other

Generic errors:

SolverForgeError::Other(String)

Error Conversion

SolverForgeError automatically converts from common error types:

// From serde_json::Error
let err: SolverForgeError = serde_json::from_str::<i32>("bad")
    .unwrap_err()
    .into();

// From std::io::Error
let err: SolverForgeError = std::fs::read("nonexistent")
    .unwrap_err()
    .into();

Using SolverForgeResult

The type alias simplifies return types:

use solverforge_core::SolverForgeResult;

fn build_model() -> SolverForgeResult<DomainModel> {
    let model = DomainModel::builder()
        .add_class(/* ... */)
        .build_validated()?;  // Returns SolverForgeResult
    Ok(model)
}

Error Handling Patterns

Match on Variants

match result {
    Ok(solution) => { /* handle success */ }
    Err(SolverForgeError::Validation(msg)) => {
        eprintln!("Model validation failed: {}", msg);
    }
    Err(SolverForgeError::Http(msg)) => {
        eprintln!("Service communication failed: {}", msg);
    }
    Err(e) => {
        eprintln!("Other error: {}", e);
    }
}

Propagate with ?

fn solve() -> SolverForgeResult<SolveResponse> {
    let model = build_model()?;
    let wasm = build_wasm(&model)?;
    let response = send_request(&wasm)?;
    Ok(response)
}

Convert to String

let error_message = format!("{}", error);

Troubleshooting

“Service not running”

Error: Http error: connection refused

Fix: Start the solver service:

let service = EmbeddedService::start(ServiceConfig::new())?;

“WASM generation failed”

Error: WasmGeneration error: Unknown class 'Shift'

Fix: Ensure domain model is set:

WasmModuleBuilder::new()
    .with_domain_model(model)  // Required!

“Validation error: No solution class”

Error: Validation error: No @PlanningSolution class found

Fix: Add PlanningSolution annotation:

DomainClass::new("Schedule")
    .with_annotation(PlanningAnnotation::PlanningSolution)

“Invalid score format”

Error: Serialization error: Invalid HardSoftScore format

Fix: Use correct format: "0hard/-5soft" not "0/-5"