The API reference documents an endpoint for removing a work-item relation:
https://developers.plane.so/api-reference/work-item-relations/remove-work-item-relation
POST /api/v1/workspaces/{workspace_slug}/projects/{project_id}/work-items/{work_item_id}/relations/remove/
{"related_issue": "<uuid>"}
That route is not registered anywhere in this repository, so it returns 404 on self-hosted instances.
What the code actually has
apps/api/plane/api/urls/work_item.py registers exactly one relations route:
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/work-items/<uuid:issue_id>/relations/",
IssueRelationListCreateAPIEndpoint.as_view(http_method_names=["get", "post"]),
name="work-item-relation-list",
),
IssueRelationListCreateAPIEndpoint (apps/api/plane/api/views/issue.py) defines get and post and nothing else. relations/remove does not appear anywhere in the tree.
Curiously, the serializer for the documented request body does exist — IssueRelationRemoveSerializer in apps/api/plane/api/serializers/issue.py, with a related_issue UUID field and the exact help text from the docs page. It is not imported anywhere, not exported from serializers/__init__.py, and not referenced by any view. It looks like the request shape was ported over but the endpoint that would consume it was not.
There is a relations/remove/ route on commit 801b3315d, but it was never merged (only on fix/comments-mention, in no tag), and it uses the issues/ prefix rather than the work-items/ prefix the docs advertise.
Versions checked
The relations list/create route arrived in #8763 and first shipped in v1.3.0. I checked v0.28.0, v1.0.0, v1.1.0, v1.2.0, v1.2.3, v1.3.0, v1.3.1, v1.4.0 and v1.4.1 — the remove sub-route is in none of them.
Reproduction
Against a self-hosted instance, with a personal API key:
# works — creates the relation, and the inverse edge
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
"$HOST/api/v1/workspaces/$WS/projects/$PROJ/work-items/$ID/relations/" \
-d '{"relation_type": "blocked_by", "issues": ["'"$OTHER"'"]}'
# works — returns the relation-type-keyed object
curl -H "X-API-Key: $KEY" \
"$HOST/api/v1/workspaces/$WS/projects/$PROJ/work-items/$ID/relations/"
# 404 {"error": "Page not found."}
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
"$HOST/api/v1/workspaces/$WS/projects/$PROJ/work-items/$ID/relations/remove/" \
-d '{"related_issue": "'"$OTHER"'"}'
Impact
Relations can be created and read through the public API but never removed, so an integration can build a dependency graph and cannot correct it. The only working path is the internal app API:
POST /api/workspaces/{slug}/projects/{project_id}/issues/{issue_id}/remove-relation/
which uses BaseSessionAuthentication and so rejects an X-API-Key. That makes it unusable from a CLI or server-to-server integration.
Either implementation would resolve this — please just let us know which, so integrations can target the right one:
- Add the documented route to the public API (
IssueRelationRemoveSerializer is already written).
- Correct the docs to state that removal is not available in v1, so nobody builds against a page that describes an endpoint that isn't there.
One incidental note
If the endpoint is implemented by reusing IssueRelationViewSet.remove_relation (apps/api/plane/app/views/issue/relation.py), that handler calls .first() and then .delete() with no None check, so removing a relation that doesn't exist raises AttributeError → HTTP 500 rather than a 404.
The API reference documents an endpoint for removing a work-item relation:
https://developers.plane.so/api-reference/work-item-relations/remove-work-item-relation
That route is not registered anywhere in this repository, so it returns 404 on self-hosted instances.
What the code actually has
apps/api/plane/api/urls/work_item.pyregisters exactly one relations route:IssueRelationListCreateAPIEndpoint(apps/api/plane/api/views/issue.py) definesgetandpostand nothing else.relations/removedoes not appear anywhere in the tree.Curiously, the serializer for the documented request body does exist —
IssueRelationRemoveSerializerinapps/api/plane/api/serializers/issue.py, with arelated_issueUUID field and the exact help text from the docs page. It is not imported anywhere, not exported fromserializers/__init__.py, and not referenced by any view. It looks like the request shape was ported over but the endpoint that would consume it was not.There is a
relations/remove/route on commit801b3315d, but it was never merged (only onfix/comments-mention, in no tag), and it uses theissues/prefix rather than thework-items/prefix the docs advertise.Versions checked
The relations list/create route arrived in #8763 and first shipped in v1.3.0. I checked v0.28.0, v1.0.0, v1.1.0, v1.2.0, v1.2.3, v1.3.0, v1.3.1, v1.4.0 and v1.4.1 — the remove sub-route is in none of them.
Reproduction
Against a self-hosted instance, with a personal API key:
Impact
Relations can be created and read through the public API but never removed, so an integration can build a dependency graph and cannot correct it. The only working path is the internal app API:
which uses
BaseSessionAuthenticationand so rejects anX-API-Key. That makes it unusable from a CLI or server-to-server integration.Either implementation would resolve this — please just let us know which, so integrations can target the right one:
IssueRelationRemoveSerializeris already written).One incidental note
If the endpoint is implemented by reusing
IssueRelationViewSet.remove_relation(apps/api/plane/app/views/issue/relation.py), that handler calls.first()and then.delete()with noNonecheck, so removing a relation that doesn't exist raisesAttributeError→ HTTP 500 rather than a 404.