stac-utils / stac-utils/pgstac
Deleting collection with items returns 500 Internal Server Error using pgstac_ingest user
Nobody has claimed this yet.
- Dominant language
- PLpgSQL
- Stars
- 223
- Forks
- 57
- PR merge metrics
- No merged PRs in 30d
Description
Hi, we are using stac-fastapi-pgstac version 6.1.5 and pgstac version 0.9.8 .
We have an AWS lambda function that loads the DB with items, it uses pgstac_ingest user to do that. In stac-fastapi-pgstac, we also use pgstac_ingest user for WRITE queries. However, when we execute DELETE collection for a collection that contains items, we get the following error:
INFO: 172.16.39.53:39460 - "DELETE /stac/api/collections/my-test-collection HTTP/1.1" 500 Internal Server Error
2026-08-03 19:52:14,458 - amazon.opentelemetry.distro.serviceevents.collectors.incident_snapshot_collector - INFO - Incident snapshot triggered: /stac/api/collections/{collection_id} DELETE (status=500, trigger=exception)
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/usr/local/lib/python3.14/site-packages/uvicorn/protocols/http/httptools_impl.py", line 409, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
self.scope, self.receive, self.send
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/usr/local/lib/python3.14/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in call
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/fastapi/applications.py", line 1159, in call
await super().call(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/starlette/applications.py", line 90, in call
await self.middleware_stack(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/starlette/middleware/errors.py", line 186, in call
raise exc
File "/usr/local/lib/python3.14/site-packages/starlette/middleware/errors.py", line 164, in call
await self.app(scope, receive, _send)
File "/otel-auto-instrumentation-python/opentelemetry/instrumentation/asgi/init.py", line 806, in call
await self.app(scope, otel_receive, otel_send)
File "/usr/local/lib/python3.14/site-packages/starlette/middleware/errors.py", line 186, in call
raise exc
File "/usr/local/lib/python3.14/site-packages/starlette/middleware/errors.py", line 164, in call
await self.app(scope, receive, _send)
File "/otel-auto-instrumentation-python/opentelemetry/instrumentation/fastapi/init.py", line 297, in call
await self.app(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/starlette/middleware/cors.py", line 96, in call
await self.simple_response(scope, receive, send, request_headers=headers)
File "/usr/local/lib/python3.14/site-packages/starlette/middleware/cors.py", line 154, in simple_response
await self.app(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/stac_fastapi/pgstac/middleware.py", line 26, in call
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/brotli_asgi/init.py", line 81, in call
await br_responder(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/brotli_asgi/init.py", line 126, in call
await self.app(scope, receive, self.send_with_brotli)
File "/otel-auto-instrumentation-python/amazon/opentelemetry/distro/serviceevents/instrumentation/fastapi_instrumentation.py", line 269, in call
await self.app(scope, receive_wrapper, send_wrapper)
File "/usr/local/lib/python3.14/site-packages/starlette/middleware/exceptions.py", line 63, in call
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
raise exc
File "/usr/local/lib/python3.14/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
await app(scope, receive, sender)
File "/usr/local/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in call
await self.app(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/starlette/routing.py", line 660, in call
await self.middleware_stack(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/starlette/routing.py", line 680, in app
await route.handle(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/starlette/routing.py", line 276, in handle
await self.app(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/fastapi/routing.py", line 134, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/usr/local/lib/python3.14/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
raise exc
File "/usr/local/lib/python3.14/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
await app(scope, receive, sender)
File "/usr/local/lib/python3.14/site-packages/fastapi/routing.py", line 120, in app
response = await f(request)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/fastapi/routing.py", line 674, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<3 lines>...
)
^
File "/usr/local/lib/python3.14/site-packages/fastapi/routing.py", line 328, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/stac_fastapi/api/routes.py", line 63, in _endpoint
return _wrap_response(await func(request=request, **request_data.kwargs()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/stac_fastapi/pgstac/transactions.py", line 322, in delete_collection
await dbfunc(conn, "delete_collection", collection_id)
File "/usr/local/lib/python3.14/site-packages/stac_fastapi/pgstac/db.py", line 199, in dbfunc
return await conn.fetchval(q, *p)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/otel-auto-instrumentation-python/opentelemetry/instrumentation/asyncpg/init.py", line 181, in _do_execute
result = await func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/asyncpg/connection.py", line 718, in fetchval
data = await self._execute(query, args, 1, timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/asyncpg/connection.py", line 1873, in _execute
result, _ = await self.__execute(
^^^^^^^^^^^^^^^^^^^^^
...<7 lines>...
)
^
File "/usr/local/lib/python3.14/site-packages/asyncpg/connection.py", line 1970, in __execute
result, stmt = await self._do_execute(
^^^^^^^^^^^^^^^^^^^^^^^
...<5 lines>...
)
^
File "/usr/local/lib/python3.14/site-packages/asyncpg/connection.py", line 2033, in _do_execute
result = await executor(stmt, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "asyncpg/protocol/protocol.pyx", line 205, in bind_execute
asyncpg.exceptions.InsufficientPrivilegeError: must be owner of table _items_45112
It appears that when the collection_delete_trigger_func() is called to drop the items partition, that partition is owned by pgstac_admin user. We switched to using pgstac_admin user for writes and that resolved this issue, but is this the intended behavior? Should pgstac_ingest user be able to delete collections that have items? Thanks!
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the delete_collection path in stac_fastapi/pgstac/transactions.py and db.py, then inspect collection_delete_trigger_func(), which the issue identifies as dropping the items partition. Reproduce collection deletion with pgstac_ingest on a collection containing items and verify the expected privilege behavior for the partition owner.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- postgresql
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100