stac-utils / stac-utils/pgstac

Deleting collection with items returns 500 Internal Server Error using pgstac_ingest user

Open
#475 6 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.