[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/rejected-operation/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# RejectedOperation

One operation of a change set that [`Project.Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) didn't apply: where it sits in the change set, and why it was rejected. You get instances from [`ApplyReport.Rejected`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md>), and as [`CandidateResult.Error`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>) when [`Project.Evaluate`](<https://docs.dhtmlx.com/planning-engine/net/api/project-evaluate.md>) can't score a candidate.

## Declaration

```csharp
namespace Plen;

public sealed class RejectedOperation : IDeepCloneable<RejectedOperation>, IEquatable<RejectedOperation>
```

Both properties are `required`, so `new RejectedOperation()` without `Path` and `Message` doesn't compile.

## Properties

| Property | Type | Description |
|---|---|---|
| `Path` | `string` | Position of the operation in the change set, as `{group}.{verb}[{index}]`. |
| `Message` | `string` | Why the operation was rejected. |

### Path

```csharp
public required string Path { get; set; }
```

`group` is `tasks`, `links`, `resources` or `assignments`; `verb` is `add`, `update` or `remove`; `index` is the zero-based position in that list of [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md>). For example, `links.add[0]` is the first entry of `changes.Links.Add`. [`AppliedOperation.Path`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md>) uses the same form, so every operation of a change set shows up exactly once in either `Applied` or `Rejected`.

In [`CandidateResult.Error`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>), a failure while solving or leveling the candidate carries the input path of that error instead, such as a field path. When that error has no path, `Path` is an empty string.

### Message

```csharp
public required string Message { get; set; }
```

The validation message, without the path, e.g. `duplicate link id` or `lag must be finite`. Each change-set type lists the messages its operations can produce; see [`LinkAdd`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/link-add.md#errors>) for an example. The text is meant for logs and diagnostics, not for matching in code.

## Methods

### DeepClone

```csharp
public RejectedOperation DeepClone()
```

Returns a copy with the same `Path` and `Message`.

### Equals

```csharp
public bool Equals(RejectedOperation? other)
public override bool Equals(object? obj)
```

Value equality: two instances are equal when `Path` and `Message` are equal. `GetHashCode` is consistent with it.

### ToString

```csharp
public override string ToString()
```

Returns a readable rendering of both properties, for logging.

## Example

Add a link whose id already exists, and read the rejection:

```csharp
using Plen;

var start = Moment.FromYmdHm(2026, 4, 6, 8, 0)
    ?? throw new InvalidOperationException("invalid date");

var data = new ProjectData
{
    Tasks =
    [
        new TaskData(1) { StartDate = start, Duration = 2.0 },
        new TaskData(2) { StartDate = start, Duration = 3.0 },
    ],
    Links = [new LinkData { Id = "L1", Source = 1, Target = 2 }],
};

var project = new Project();
project.Solve(data, new SolveOptions());

var changes = new SchedulingChanges();
changes.Links.Add.Add(new LinkAdd { Id = "L1", Source = 2, Target = 1 });

var report = project.Apply(changes);
foreach (var rejected in report.Rejected)
    Console.WriteLine($"{rejected.Path}: {rejected.Message}");
// links.add[0]: duplicate link id
```

A rejection sets [`ApplyReport.NeedsResync`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md>); to continue, see [Recover from rejected changes](<https://docs.dhtmlx.com/planning-engine/net/how-to/recover-from-rejected-changes.md>).

## Related

- [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md>) - the report that lists rejections
- [`Project.Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) - the call that rejects operations
- [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md#operation-order>) - operation order and paths
- [`CandidateResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>) - carries a rejection as its error
- [Recover from rejected changes](<https://docs.dhtmlx.com/planning-engine/net/how-to/recover-from-rejected-changes.md>) - getting the project working again
