Skip to content

Error deleting attachments via API #6859

@grantfitzsimmons

Description

@grantfitzsimmons

Describe the bug
When trying to remove an attachment or {table}attachment (e.g. collectionobjectattachment, collectingeventattachment, etc.) record via the API (both via direct API delete and using the "delete" button on the data entry forms), it fails.

To Reproduce
Steps to reproduce the behavior:

  1. Go to a CollectionObjectAttachment record directly (can grab the direct URL from the form meta menu when viewing an attachment)

  2. Attempt to delete it

  3. See error:

    {"exception": "AssertionError", "message": "attempt to add object with null id to audit log",
    
AssertionErrorDelete.mov
  1. Go to the associated Attachment record directly (or any attachment record linked to a joining {table}attachment record)

  2. Attempt to delete it

  3. See error:

    {"exception": "ProtectedError", "message": "Cannot delete some instances of model 'Attachment' because they are referenced through protected foreign keys: 'Collectionobjectattachment.attachment'.", "data": [{"Model": "CollectionObjectAttachment", "Id": 4735, "Non-Null Fields": ["collectionmemberid: 4", "ordinal: 0", "timestampcreated: 2025-07-01 08:52:27", "timestampmodified: 2025-07-01 08:52:27", "version: 0", "attachment: 5494", "collectionobject: 51733", "createdbyagent: 3"]}], "traceback": "Traceback (most recent call last):\n  File \"/opt/specify7/ve/lib/python3.9/site-packages/django/core/handlers/base.py\", line 197, in _get_response\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\n  File \"/opt/specify7/ve/lib/python3.9/site-packages/django/views/decorators/cache.py\", line 40, in _cache_controlled\n    response = viewfunc(request, *args, **kw)\n  File \"/opt/specify7/specifyweb/specify/views.py\", line 76, in view\n    return dispatch_func(request, *args, **kwargs)\n  File \"/opt/specify7/specifyweb/specify/api.py\", line 196, in resource_dispatch\n    delete_resource(request.specify_collection,\n  File \"/usr/lib/python3.9/contextlib.py\", line 79, in inner\n    return func(*args, **kwds)\n  File \"/opt/specify7/specifyweb/specify/api.py\", line 863, in delete_resource\n    return delete_obj(obj, (make_default_deleter(collection, agent)), version)\n  File \"/opt/specify7/specifyweb/specify/api.py\", line 894, in delete_obj\n    obj.delete()\n  File \"/opt/specify7/ve/lib/python3.9/site-packages/django/db/models/base.py\", line 1131, in delete\n    collector.collect([self], keep_parents=keep_parents)\n  File \"/opt/specify7/ve/lib/python3.9/site-packages/django/db/models/deletion.py\", line 355, in collect\n    raise ProtectedError(\ndjango.db.models.deletion.ProtectedError: (\"Cannot delete some instances of model 'Attachment' because they are referenced through protected foreign keys: 'Collectionobjectattachment.attachment'.\", {<Collectionobjectattachment: Collectionobjectattachment object (4735)>})\n"}
    

Expected behavior
Deleting a collectionobjectattachment should delete the attachment record as long as it is not referenced anywhere else (attachments can be shared with multiple join records).

Deleting an attachment record should delete all associated {table}attachment records.

In both cases, it should not result in an error and the actual attachment file should be deleted.

Crash Report
Specify 7 System Information - 2025-07-01T16_14_24.296Z.txt

v711-prerelease and v7.10.2.3, sp7demofish abb2d47

Reported By
NHMD via the Speciforum

Hi,

Specify v7.9.6.2

Im trying to make use of the api specifically the delete endpoint for attachments and collectionobjectattachments.
When trying to delete the collectionobjectattachment i get this error back:

500 Undocumented Error: Internal Server Error

{"exception": "AssertionError", "message": "attempt to add object with null id to audit log", "data": "None", "traceback": "Traceback (most recent call last):\n  File \"/opt/specify7/ve/lib/python3.8/site-packages/django/core/handlers/base.py\", line 181, in _get_response\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\n  File \"/opt/specify7/specifyweb/specify/views.py\", line 34, in wrapped\n    return view(request, *args, **kwargs)\n  File \"/opt/specify7/ve/lib/python3.8/site-packages/django/views/decorators/cache.py\", line 31, in _cache_controlled\n    response = viewfunc(request, *args, **kw)\n  File \"/opt/specify7/specifyweb/specify/views.py\", line 70, in view\n    return dispatch_func(request, *args, **kwargs)\n  File \"/opt/specify7/specifyweb/specify/api.py\", line 177, in resource_dispatch\n    delete_resource(request.specify_collection,\n  File \"/usr/lib/python3.8/contextlib.py\", line 75, in inner\n    return func(*args, **kwds)\n  File \"/opt/specify7/specifyweb/specify/api.py\", line 636, in delete_resource\n    return delete_obj(obj, version, collection=collection, agent=agent)\n  File \"/opt/specify7/specifyweb/specify/api.py\", line 660, in delete_obj\n    delete_obj(dep, version, parent_obj=obj, collection=collection, agent=agent, clean_predelete=clean_predelete)\n  File \"/opt/specify7/specifyweb/specify/api.py\", line 650, in delete_obj\n    auditlog.remove(obj, agent, parent_obj)\n  File \"/opt/specify7/specifyweb/specify/auditlog.py\", line 63, in remove\n    log_obj = self._log(auditcodes.REMOVE, obj, agent, parent_record)\n  File \"/opt/specify7/specifyweb/specify/auditlog.py\", line 89, in _log\n    assert obj.id is not None, \"attempt to add object with null id to audit log\"\nAssertionError: attempt to add object with null id to audit log\n"}

Metadata

Metadata

Assignees

Labels

2 - APIIssues that are related to the APIs2 - AttachmentsIssues that are related to attachments

Type

No fields configured for Bug.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions