Gvisor sandboxing creates error in time zone formula

Dear community,

We are running a self-hosted Grist version 1.7.2 on Docker, and I tried to enable sandboxing for documents.
As a result, one formula stopped working. Here is the part that is problematic:

from zoneinfo import ZoneInfo
return ZoneInfo('Europe/Paris')

We reproduced the error on another instance. Here is the full error message:

2025-08-19 13:32:54.548 - info: Sandbox stderr: [INFO] [engine] Formula error in [Table1.A]: Traceback (most recent call last):
  File "/usr/local/lib/python3.11/zoneinfo/_common.py", line 12, in load_tzdata
    return resources.files(package_name).joinpath(resource_name).open("rb")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/importlib/resources/_common.py", line 22, in files
    return from_package(get_package(package))
                        ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/importlib/resources/_common.py", line 53, in get_package
    resolved = resolve(package)
               ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/importlib/resources/_common.py", line 44, in resolve
    return cand if isinstance(cand, types.ModuleType) else importlib.import_module(cand)
                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1126, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1126, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'tzdata'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/grist/sandbox/grist/engine.py", line 981, in _recompute_one_cell
    result = col.method(record, table.user_table)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "usercode", line 17, in A
    return print(ZoneInfo('Europe/Paris'))
                 ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/zoneinfo/_common.py", line 24, in load_tzdata
    raise ZoneInfoNotFoundError(f"No time zone found with key {key}")
zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key Europe/Paris'

On the Python documentation, it says:

By default, zoneinfo uses the system’s time zone data if available; if no system time zone data is available, the library will fall back to using the first-party tzdata package available on PyPI.

I can see that the package is already installed on the Grist docker image so it shouldn’t be needed to import the package.

Way to reproduce:

  1. Run the command sudo docker run --env GRIST_SANDBOX_FLAVOR=gvisor -p 8484:8484 -it gristlabs/grist
  2. Go to localhost:8484 and create an empty document.
  3. Set the formula:
from zoneinfo import ZoneInfo
return ZoneInfo('Europe/Paris')
  1. You can see the error message in the terminal.
  2. Run the command sudo docker run -p 8484:8484 -it gristlabs/grist to test the above without gvisor.

Could you please advise?

1 Like

I can see that the package is already installed on the Grist docker image so it shouldn’t be needed to import the package.

The sandboxes only get access to parts of that docker image, controlled via preserve() calls in a script:

What is the path to the time zone data? It may be that it isn’t in a directory that is already shared, and to support what you want to do it needs to be shared with the sandboxes.

An alternative could be to install tzdata:

Dear @paul-grist,

Thank you very much for your reply! Here is the path to the time zone data: /usr/share/zoneinfo

Hello @paul-grist,

We’ve found a way to make it work! We have added a variable in the config file as follows:
GVISOR_EXTRA_DIRS: "/usr/share/zoneinfo"

We found the info here: grist-core/sandbox/gvisor/run.py at e6be393192adb3d33fac9b2cf2a7a9e72fdc8b59 · gristlabs/grist-core · GitHub

However, it’s not documented in your README.

Is there a reason for that?

Glad you found a way to do it. It would be great to add that variable to the README for others.