GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — dbm.sqlite breaks multi-threaded shelve usage · Issue #131918 · python/cpython

dbm.sqlite breaks multi-threaded shelve usage #131918

New issue
Copy link
New issue
Copy link
Open
Open
dbm.sqlite breaks multi-threaded shelve usage#131918
Copy link
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-sqlite3type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@meghprkh
meghprkh
opened on Mar 30, 2025
Issue body actions

Bug report

Bug description:

dbm backends were previously thread safe, but I think dbm.sqlite introduced in #114481 is not.

I am not sure if the resolution should be to add a doc comment to shelve/dbm or some other way to fix it, say specifying a preferred backend or multithreading argument in shelve.open as an argument. (Or if there is a way to fix this in dbm.sqlite itself)

Example code:

from concurrent.futures import ThreadPoolExecutor
import shelve

CACHE = shelve.open('test')

def check_set_cache(value):
    if 'value' in CACHE:
        print(CACHE['value'])
    CACHE['value'] = value
    return CACHE['value']

jobs = list(range(1, 100))
executor = ThreadPoolExecutor(max_workers=5)
entries = list(executor.map(check_set_cache, jobs))
print(entries)

Log

Traceback (most recent call last):
  File "/usr/lib64/python3.13/dbm/sqlite3.py", line 79, in _execute
    return closing(self._cx.execute(*args, **kwargs))
                   ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 140036133836608 and this is thread id 140035884230336.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/megh/pybug/reproduce.py", line 14, in <module>
    entries = list(executor.map(check_set_cache, jobs))
  File "/usr/lib64/python3.13/concurrent/futures/_base.py", line 619, in result_iterator
    yield _result_or_cancel(fs.pop())
          ~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/usr/lib64/python3.13/concurrent/futures/_base.py", line 317, in _result_or_cancel
    return fut.result(timeout)
           ~~~~~~~~~~^^^^^^^^^
  File "/usr/lib64/python3.13/concurrent/futures/_base.py", line 449, in result
    return self.__get_result()
           ~~~~~~~~~~~~~~~~~^^
  File "/usr/lib64/python3.13/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/usr/lib64/python3.13/concurrent/futures/thread.py", line 59, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/megh/pybug/reproduce.py", line 7, in check_set_cache
    if 'value' in CACHE:
       ^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/shelve.py", line 102, in __contains__
    return key.encode(self.keyencoding) in self.dict
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen _collections_abc>", line 817, in __contains__
  File "/usr/lib64/python3.13/dbm/sqlite3.py", line 89, in __getitem__
    with self._execute(LOOKUP_KEY, (key,)) as cu:
         ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/dbm/sqlite3.py", line 81, in _execute
    raise error(str(exc))
dbm.sqlite3.error: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 140036133836608 and this is thread id 140035884230336.

(Observed here beancount/beanprice#91 )

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

  • gh-131918: Add _ThreadLocalSqliteConnection in dbm.sqlite #131920

Activity

  1. meghprkh
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Mar 30, 2025
  2. erlend-aasland
    added
    topic-sqlite3
    on Mar 30, 2025
  3. erlend-aasland
    added this to sqlite3 issuesand dbm and shelve issueson Mar 30, 2025
  4. meghprkh
    added 2 commits that reference this issue on Mar 30, 2025

    Add _ThreadLocalSqliteConnection in dbm.sqlite (fixes python#131918)

    This issue will close once commit 3818ab7 is merged into the 'main' branch.
    3818ab7

    pythongh-131918: Add _ThreadLocalSqliteConnection in dbm.sqlite

    This issue will close once commit bbbdbc3 is merged into the 'main' branch.
    bbbdbc3
  5. picnixz
    added
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    on Mar 30, 2025
  6. brianschubert commented on Mar 30, 2025

    @brianschubert
    brianschubert
    on Mar 30, 2025
    Contributor
    More actions

    dbm backends were previously thread safe

    Is this actually promised anywhere? I don't see any mention of thread safety in the current docs. Some language should probably be added to explain what sort of thread-safety guarantees users can expect (if any?)

    Reacted by Erlend E. Aasland, Serhiy Storchaka and Furkan Onder
  7. serhiy-storchaka commented on Jul 6, 2025

    @serhiy-storchaka
    serhiy-storchaka
    on Jul 6, 2025
    Member
    More actions

    It does not look to me that dbm.dumb was thread-safe.

  8. furkanonder
    added
    3.13only security fixesonly security fixes
    3.14bugs and security fixesbugs and security fixes
    3.15bugs and security fixesbugs and security fixes
    on Aug 21, 2025
  9. guillaume-fr commented on Oct 28, 2026

    @guillaume-fr
    guillaume-fr
    on Oct 28, 2026
    More actions

    SQLite objects created in a thread can only be used in that same thread.

    @brianschubert , isn't it even more strict than not being thread-safe?

    I agree relying on undocumented thread-safety can be UB. Now, with no specific documentation, I'd expect objects to support thread agility : being used from different threads, as long as it's properly locked. Isn't introducing such specific single-thread restriction, on the default provider, a breaking change?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-sqlite3type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    • sqlite3 issues
      Status
      No status
      Show more project fields
    • dbm and shelve issues
      Status
      No status
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.