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


# Conflict

A scheduling conflict found while placing tasks. You don't build it yourself. Read it from [`ScheduleResult::conflicts`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/schedule-result.md#conflicts>), which lists every conflict of the run. A conflict is data in the result, not an error: the run still succeeds and returns dates.

## Declaration

```rust
#[derive(Clone, Debug, PartialEq)]
pub enum Conflict {
    ConstraintViolation {
        task: Id,
        constraint: ConstraintType,
        violation: Violation,
        required: DateTime,
        actual: DateTime,
    },
    CalendarNonWorking {
        task: Id,
        proposed: DateTime,
        snapped: DateTime,
    },
}
```

With the `serde` feature, it also implements `Serialize` and `Deserialize`; see [Serialization](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/conflict.md#serialization>).

## Variants

| Variant | When it occurs |
|---|---|
| `ConstraintViolation` | A task's constraint placed it at a date its driving dependency link doesn't allow. The constraint wins, and the task keeps the constraint's date. Reported only when [`SchedulingConfig::apply_constraints`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/scheduling-config.md#apply_constraints>) is `true`. |
| `CalendarNonWorking` | A summary moved as one block and a descendant task landed on non-working time of its calendar. Reported only when [`SchedulingConfig::strict_calendar`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/scheduling-config.md#strict_calendar>) is `true`. |

### ConstraintViolation

| Field | Type | Description |
|---|---|---|
| `task` | [`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>) | The task or summary whose constraint won. |
| `constraint` | [`ConstraintType`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/constraint-type.md>) | The constraint that placed the task: the task's own, or a dated constraint inherited from a summary. |
| `violation` | [`Violation`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/violation.md>) | Which bound the link contradicts. `EarliestStart` and `LatestStart` compare start dates, `EarliestEnd` and `LatestEnd` compare end dates. |
| `required` | [`DateTime`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/date-time.md>) | The date the constraint gave the task. It's the date the task got in the result. |
| `actual` | [`DateTime`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/date-time.md>) | The date the driving link would have given the task. |

### CalendarNonWorking

| Field | Type | Description |
|---|---|---|
| `task` | [`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>) | The descendant task that landed on non-working time. |
| `proposed` | [`DateTime`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/date-time.md>) | The task's new start (its new end in a backward-scheduled project), on non-working time. |
| `snapped` | [`DateTime`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/date-time.md>) | The date the task keeps. Currently it's always equal to `proposed`: the task isn't moved to working time. |

## Serialization

With the `serde` feature, a `Conflict` serializes as an object tagged by `kind`. The variant name is written in kebab-case, field names in camelCase:

```json
{
  "kind": "constraint-violation",
  "task": "build",
  "constraint": "snlt",
  "violation": "latest-start",
  "required": "2026-01-06 08:00",
  "actual": "2026-01-07 08:00"
}
```

```json
{ "kind": "calendar-non-working", "task": "b", "proposed": "2026-01-10 08:00", "snapped": "2026-01-10 08:00" }
```

## Example

`build` must start no later than Tuesday, but its predecessor `design` ends on Wednesday. The constraint wins, and the result reports the conflict.

```rust
use plen_core::{
    schedule, Conflict, ConstraintType, DateTime, LinkData, LinkType, ProjectData,
    SchedulingConfig, SolveOptions, TaskData,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let monday = DateTime::from_ymd_hm(2026, 1, 5, 8, 0).ok_or("invalid date")?;
    let tuesday = DateTime::from_ymd_hm(2026, 1, 6, 8, 0).ok_or("invalid date")?;

    let mut design = TaskData::new("design");
    design.start_date = Some(monday);
    design.duration = Some(2.0);

    let mut build = TaskData::new("build");
    build.start_date = Some(monday);
    build.duration = Some(1.0);
    build.constraint_type = Some(ConstraintType::Snlt);
    build.constraint_date = Some(tuesday);

    let data = ProjectData {
        config: SchedulingConfig { apply_constraints: true, ..Default::default() },
        tasks: vec![design, build],
        links: vec![LinkData {
            id: "design-build".into(),
            source: "design".into(),
            target: "build".into(),
            link_type: LinkType::Fs,
            lag: 0.0,
            lag_unit: None,
        }],
        ..Default::default()
    };

    let result = schedule(data, &SolveOptions::default())?;

    for conflict in &result.conflicts {
        match conflict {
            Conflict::ConstraintViolation { task, constraint, violation, required, actual } => {
                println!(
                    "{task}: {} {violation:?}, constraint gives {required}, link wants {actual}",
                    constraint.as_str()
                );
                // build: snlt LatestStart, constraint gives 2026-01-06 08:00, link wants 2026-01-07 08:00
            }
            Conflict::CalendarNonWorking { task, proposed, .. } => {
                println!("{task}: on non-working time at {proposed}");
            }
        }
    }
    Ok(())
}
```

## Related

- [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/schedule-result.md#conflicts>) - lists the conflicts of a run
- [`Violation`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/violation.md>) - the bound a constraint conflict breaks
- [`SchedulingConfig`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/scheduling-config.md>) - holds the flags that enable each conflict kind
- [Links, constraints and summaries](<https://docs.dhtmlx.com/planning-engine/rust/scheduling/links-constraints-summaries.md#detecting-a-constraint-that-a-link-breaks>) - triggers and reads a constraint conflict
- [Reading results](<https://docs.dhtmlx.com/planning-engine/rust/scheduling/reading-results.md#conflicts>) - handles conflicts in a result
