[Canonical page](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Error

The error returned by every fallible `plen-core` call, as `Result<T, Error>`. It's an enum with two variants: invalid input, or a call that doesn't fit the project's current state. You get it from the methods of [`Project`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md>) and from [`schedule`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/schedule.md>).

## Declaration

```rust
#[derive(Debug)]
pub enum Error {
    Input(InputError),
    Project(ProjectError),
}

impl std::error::Error for Error {}
impl std::fmt::Display for Error {}
impl From<InputError> for Error {}
impl From<ProjectError> for Error {}
```

`Error` isn't `Clone` or `PartialEq`. Match on it with `match` or `matches!` instead of comparing with `==`.

## Variants

| Variant | When it occurs |
|---|---|
| `Input(`[`InputError`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/input-error.md>)`)` | The data or options passed to the call are invalid. The project's state is unchanged. |
| `Project(`[`ProjectError`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/project-error.md>)`)` | The call doesn't fit the project's current state, for example a preview on an unsolved project. The project's state is unchanged. |

Conflicts, cycles, failure to converge and rejected [`apply`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#apply>) operations aren't errors. They're reported inside the call's result.

### Which calls return each variant

| Call | `Error::Input` | `Error::Project` |
|---|---|---|
| [`Project::solve`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#solve>) | yes | yes |
| [`Project::preview`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#preview>) | yes | yes |
| [`Project::analyze`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#analyze>) | yes | no |
| [`Project::apply`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#apply>) | no | yes |
| [`Project::level`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#level>) | yes | yes |
| [`Project::load_profile`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#load_profile>) | yes | yes |
| [`Project::evaluate`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#evaluate>), [`Project::evaluate_with`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#evaluate_with>) | yes | yes |
| [`Project::suggest_assignments`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#suggest_assignments>) | yes | yes |
| [`Project::roster`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#roster>) | no | yes |
| [`schedule`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/schedule.md>) | yes | no |

Each method in [`Project`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md>) lists the exact conditions.

## Display

Both variants are transparent. `Display` prints the inner error's text:

- `Error::Input`: the `message` of the [`InputError`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/input-error.md>), without its `path`
- `Error::Project`: the variant's name in kebab-case: `no-baseline`, `stale-baseline` or `needs-resync`

## Conversions

| Impl | Result |
|---|---|
| `From<`[`InputError`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/input-error.md>)`>` | `Error::Input` |
| `From<`[`ProjectError`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/project-error.md>)`>` | `Error::Project` |
| `From<`[`MatchError`](<https://docs.dhtmlx.com/planning-engine/rust/api/assign/match-error.md>)`>` | `MatchError::Invalid { path, message }` becomes `Error::Input` with kind `Validation` and that `path` and `message`. `MatchError::Project(e)` becomes `Error::Project(e)`. Defined in `plen-assign`. |

With these impls, `?` turns an `InputError`, `ProjectError` or `MatchError` into `Error` in a function that returns `Result<_, Error>`. Since `Error` implements `std::error::Error`, `?` also turns it into `Box<dyn std::error::Error>`.

## Example

```rust
use plen_core::{Error, PreviewOptions, Project, ProjectError, SchedulingChanges};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let project = Project::default();

    // The project has never been solved, so preview fails with NoBaseline.
    match project.preview(&SchedulingChanges::default(), &PreviewOptions::default()) {
        Ok(result) => println!("{} tasks would move", result.updates.len()),
        Err(Error::Project(ProjectError::NoBaseline)) => println!("solve the project first"),
        Err(Error::Input(e)) => println!("invalid input at {:?}: {}", e.path, e.message),
        Err(e) => return Err(e.into()),
    }
    Ok(())
}
```

For recovery patterns for each variant, see [Error handling](<https://docs.dhtmlx.com/planning-engine/rust/error-handling.md>).

## Related

- [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/apply-report.md>) - where rejected `apply` operations are reported instead
- [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/schedule-result.md>) - where conflicts, cycles and non-convergence are reported instead
- [Scheduling a Project](<https://docs.dhtmlx.com/planning-engine/rust/scheduling/scheduling-a-project.md>) - shows `?` on solve calls that return this error
- [Accept messy input](<https://docs.dhtmlx.com/planning-engine/rust/how-to/accept-messy-input.md>) - shows how to repair data instead of getting `Error::Input`
