Skip to content

[bug]: Any update to a completed work item will update the completed at date #9012

@jordent

Description

@jordent

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

Experiencing:

Any update to a completed work item updates the completed_at timestamp to the current date/time.

This happens regardless of what field is being updated. For example:

  • Updating a completed work item in the UI changes completed_at
  • Sending a PATCH request for an unrelated field changes completed_at
  • Sending an empty PATCH request also changes completed_at

Because of this, completed_at does not represent when the work item was actually completed. Instead, it effectively becomes “the last time this completed work item was saved”, which is redundant because we already have updated_at.

This also makes it impossible to reliably preserve historical completion dates during imports or migrations. Even if completed_at is manually set or backfilled, any future edit to the completed work item overwrites that value with the current timestamp.

Expected Behavior:

completed_at should only be updated when a work item transitions from a non-completed state group into a completed state group.

For example:

  • If a work item moves from Started to Completed, set completed_at to the current timestamp, unless a valid completed_at value was explicitly provided through the API.
  • If a work item is already completed and is updated, preserve the existing completed_at value.
  • If a work item moves out of a completed state group, clear completed_at or handle it according to the intended reopen behavior.

The API should also respect an explicitly provided completed_at value when creating or updating a work item in a completed state. At minimum, updates to unrelated fields should not overwrite an existing completed_at timestamp.

Steps to reproduce

  1. Send a request to create a new issue with a completed state of done. project_id is valid, and state is the valid id for the 'Done' state for that project.

    Route:
    POST /api/v1/workspaces/pfp/projects/{project_id}/work-items/

    Body:

    {
        "name": "Test Work Item",
        "state": "3dd0f6a1-ead7-44ee-af95-1197eb501225"
    }

    Response: 201 Created

    {
        "id": "c46ac60f-44c8-4fe8-a428-b25ec2b599c0",
        "created_at": 2026-05-04T13:00:13.291448-04:00,
        "updated_at": "2026-05-04T13:00:13.291487-04:00",
        "deleted_at": null,
        "name": "Test Work Item",
        "description_html": "<p></p>",
        "completed_at": "2026-05-04T13:00:13.262088-04:00",
        "state": "3dd0f6a1-ead7-44ee-af95-1197eb501225"
    }
  2. Patch same work item with modified description or something.

    Route:
    PATCH /api/v1/workspaces/pfp/projects/{project_id}/work-items/c46ac60f-44c8-4fe8-a428-b25ec2b599c0/

    Body:

    {
        "description_html": "<p>test</p>"
    }

    Response: 200 OK

    {
        "id": "c46ac60f-44c8-4fe8-a428-b25ec2b599c0",
        "created_at": "2026-05-04T13:00:13.332596-04:00",
        "updated_at": "2026-05-04T13:03:08.799782-04:00",
        "deleted_at": null,
        "name": "Test Work Item",
        "description_html": "<p>test</p>",
        "completed_at": "2026-05-04T13:03:08.791727-04:00",
        "state": "3dd0f6a1-ead7-44ee-af95-1197eb501225"
    }

    Note that completed_at has been updated to the current date along with updated_at.

  3. Patch same work item with empty body.

    Route:
    PATCH /api/v1/workspaces/pfp/projects/{project_id}/work-items/c46ac60f-44c8-4fe8-a428-b25ec2b599c0/

    Body:

No request body was sent.

Response: 200 OK
```json
{
    "id": "c46ac60f-44c8-4fe8-a428-b25ec2b599c0",
    "created_at": "2026-05-04T13:00:13.332596-04:00",
    "updated_at": "2026-05-04T13:05:12.878771-04:00",
    "deleted_at": null,
    "name": "Test Work Item",
    "description_html": "<p>test</p>",
    "completed_at": "2026-05-04T13:05:12.868085-04:00",
    "state": "3dd0f6a1-ead7-44ee-af95-1197eb501225"
}
```

Note that `completed_at` has been updated to the current date along with `updated_at`.
  1. Can replicate the same behavior by making edits in the UI and watching the completed_at values for the work item via API.

Environment

Production

Browser

None

Variant

Self-hosted

Version

v1.3.0

Metadata

Metadata

Assignees

Labels

planesync issues to Plane🐛bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions