snowflakedb / snowflakedb/snowflake-connector-python

SNOW-3794266: OAuth token caching on Windows crashes with unhandled CredWrite error 1783 when the token exceeds the Credential Manager blob limit

Open
#2,930 3 comments 1 reaction 1 assignee View on GitHub

@sfc-gh-snow-drivers-warsaw-dl is already working on this.

Since Jul 16, 2026.

bug status-triage_done
Dominant language
Python
Stars
730
Forks
574
Avg merge
5h 45m
Merged PRs (30d)
16

Description

Python version

Python 3.13.3 (Windows Store / MSIX distribution, but reproducible on regular CPython too)

Operating system and processor architecture

Windows 11 x64

Installed packages
acryl-datahub==1.5.0.1
agate==1.9.1
aiofile==3.9.0
aiohappyeyeballs==2.6.1
aiohttp==3.13.5
aiosignal==1.4.0
alembic==1.18.4
altair==6.0.0
annotated-doc==0.0.4
annotated-types==0.7.0
anyio==4.13.0
argon2-cffi==25.1.0
argon2-cffi-bindings==25.1.0
asgiref==3.11.1
asn1crypto==1.5.1
asttokens==2.4.1
attrs==26.1.0
Authlib==1.6.9
av==17.0.0
avro==1.12.1
avro-gen3==0.7.16
babel==2.18.0
backoff==2.2.1
bandit==1.9.4
bcrypt==5.0.0
beartype==0.22.9
beautifulsoup4==4.14.3
black==26.3.1
blinker==1.9.0
boto3==1.42.76
botocore==1.42.76
cached-property==2.0.1
cachetools==7.0.5
caio==0.9.25
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.6
click==8.4.1
click-default-group==1.2.4
click-spinner==0.1.10
cloudpickle==3.1.1
colorama==0.4.6
coverage==7.13.5
cronsim==2.7
cryptography==46.0.0
ctranslate2==4.7.1
cyclopts==4.10.1
daff==1.4.2
dbt-adapters==1.24.2
dbt-common==1.38.0
dbt-core==1.11.11
dbt-extractor==0.6.0
dbt-metricflow==0.13.0
dbt-protos==1.0.514
dbt-semantic-interfaces==0.9.0
dbt-snowflake==1.11.5
deepdiff==8.6.2
Deprecated==1.3.1
devtools==0.12.2
diskcache==5.6.3
distro==1.9.0
dnspython==2.8.0
docker==7.1.0
docstring_parser==0.17.0
docutils==0.22.4
email-validator==2.3.0
et_xmlfile==2.0.0
exceptiongroup==1.3.1
execnet==2.1.2
executing==2.2.1
expandvars==1.1.2
fakeredis==2.34.1
fastapi==0.135.3
faster-whisper==1.2.1
fastmcp==3.1.1
filelock==3.25.2
flatbuffers==25.12.19
frozenlist==1.8.0
fsspec==2026.2.0
git-filter-repo==2.47.0
gitdb==4.0.12
GitPython==3.1.44
googleapis-common-protos==1.75.0
graphql-core==3.2.8
graphviz==0.21
greenlet==3.3.2
h11==0.16.0
halo==0.0.31
hf-xet==1.4.2
httpcore==1.0.9
httptools==0.8.0
httpx==0.28.1
httpx-sse==0.4.3
huggingface_hub==1.7.1
humanfriendly==10.0
hypothesis==6.151.9
icecream==2.1.10
id==1.5.0
idna==3.11
ijson==3.5.0
importlib_metadata==8.7.1
iniconfig==2.3.0
invoke==3.0.0
isodate==0.7.2
isort==8.0.1
itsdangerous==2.2.0
jaraco.classes==3.4.0
jaraco.context==6.1.2
jaraco.functools==4.4.0
Jinja2==3.1.6
jiter==0.13.0
jmespath==1.1.0
jq==1.11.0
json-logic==0.7.0a0
jsonref==1.1.0
jsonschema==4.26.0
jsonschema-path==0.4.5
jsonschema-specifications==2025.9.1
keyring==25.7.0
keyrings.alt==5.0.2
keyrings.cryptfile==1.3.9
langfuse==4.6.1
leather==0.4.1
line_profiler==5.0.2
llvmlite==0.46.0
log-symbols==0.0.14
lupa==2.6
lxml==6.0.2
Mako==1.3.10
mando==0.7.1
markdown-it-py==4.0.0
MarkupSafe==3.0.3
mashumaro==3.14
mcp==1.26.0
mdurl==0.1.2
metricflow==0.211.0
mixpanel==5.1.0
more-itertools==10.8.0
mpmath==1.3.0
msal==1.35.1
msgpack==1.1.2
multidict==6.7.1
mypy_extensions==1.1.0
narwhals==2.18.0
networkx==3.6.1
nodeenv==1.10.0
numba==0.64.0
numpy==2.4.3
nvidia-ml-py==13.595.45
onnxruntime==1.24.4
openai==2.30.0
openapi-pydantic==0.5.1
openlineage-python==1.50.0
openpyxl==3.1.5
opentelemetry-api==1.41.1
opentelemetry-exporter-otlp-proto-common==1.41.1
opentelemetry-exporter-otlp-proto-http==1.41.1
opentelemetry-proto==1.41.1
opentelemetry-sdk==1.41.1
opentelemetry-semantic-conventions==0.62b1
orderly-set==5.5.0
orjson==3.11.7
packaging==25.0
pandas==2.3.3
paramiko==4.0.0
parsedatetime==2.6
pathable==0.5.0
pathspec==1.1.1
pathvalidate==3.3.1
pillow==12.1.1
platformdirs==4.9.4
playwright==1.60.0
plotly==5.24.1
pluggy==1.6.0
progressbar2==4.5.0
prometheus_client==0.24.1
prompt_toolkit==3.0.51
propcache==0.4.1
protobuf==6.33.6
psutil==5.9.8
psycopg2-binary==2.9.11
PuLP==3.3.2
py-cpuinfo==9.0.0
py-key-value-aio==0.4.4
py-key-value-shared==0.3.0
pyarrow==23.0.1
pycparser==3.0
pycryptodome==3.23.0
pydantic==2.12.5
pydantic-settings==2.13.1
pydantic_core==2.41.5
pydeck==0.9.1
pydocket==0.18.2
pyee==13.0.1
Pygments==2.19.2
pyinstrument==5.1.2
PyJWT==2.12.1
PyMuPDF==1.27.2.2
PyNaCl==1.6.2
pyodbc==5.3.0
pyOpenSSL==25.3.0
pypdf==6.12.2
pyperclip==1.11.0
pyreadline3==3.5.4
pyright==1.1.408
pytest==9.0.2
pytest-anyio==0.0.0
pytest-benchmark==5.2.3
pytest-cov==7.0.0
pytest-mock==3.15.1
pytest-sugar==1.1.1
pytest-timeout==2.4.0
pytest-xdist==3.8.0
python-dateutil==2.9.0.post0
python-docx==1.2.0
python-dotenv==1.2.1
python-json-logger==4.0.0
python-multipart==0.0.22
python-pptx==1.0.2
python-slugify==8.0.4
python-utils==3.9.1
pytimeparse==1.1.8
pytokens==0.4.1
pytz==2025.2
pywin32==311
pywin32-ctypes==0.2.3
PyYAML==6.0.2
radon==6.0.1
RapidFuzz==3.14.5
redis==7.4.0
referencing==0.37.0
regex==2026.2.28
requests==2.32.4
requests-file==3.0.1
requirements-parser==0.13.0
rich==14.0.0
rich-rst==1.3.2
rpds-py==0.30.0
ruamel.yaml==0.18.17
ruamel.yaml.clib==0.2.15
ruff==0.15.7
s3transfer==0.16.0
scalene==2.2.1
scipy==1.17.1
sentry-sdk==2.57.0
setuptools==80.8.0
shellingham==1.5.4
six==1.17.0
smmap==5.0.3
sniffio==1.3.1
snowflake-cli==3.16.0
snowflake-connector-python==3.18.0
snowflake-labs-mcp @ file:///C:/Users/carlos.alemany/OneDrive%20-%20civica-soft.com/Documentos/UEFA/snowflake-mcp
snowflake-snowpark-python==1.41.0
snowflake.core==1.10.0
snowplow-tracker==1.1.0
sortedcontainers==2.4.0
soupsieve==2.8.3
spinners==0.0.24
SQLAlchemy==2.0.44
sqlglot==30.0.3
sqlparse==0.5.3
sse-starlette==3.3.3
starlette==1.0.0
stevedore==5.7.0
streamlit==1.58.0
sympy==1.14.0
tabulate==0.9.0
tenacity==9.1.4
termcolor==3.3.0
text-unidecode==1.3
tiktoken==0.12.0
tokenizers==0.22.2
toml==0.10.2
tomlkit==0.13.3
tornado==6.5.5
tqdm==4.67.3
ty==0.0.25
typer==0.17.3
typing-inspect==0.9.0
typing-inspection==0.4.2
typing_extensions==4.15.0
tzdata==2025.3
tzlocal==5.3.1
uncalled-for==0.2.0
update-checker==0.18.0
urllib3==2.6.3
uvicorn==0.42.0
vulture==2.16
watchdog==6.0.0
watchfiles==1.1.1
wcwidth==0.6.0
websockets==16.0
wheel==0.47.0
wrapt==1.17.3
xlsxwriter==3.2.9
yarl==1.23.0
zipp==3.23.0
What did you do?

I set up a snow CLI connection with OAuth and token caching enabled:

[connections.oauth-conn]
account = "<account>.<region>"
user = "<user>"
authenticator = "OAUTH_AUTHORIZATION_CODE"
client_store_temporary_credential = true

(ALTER ACCOUNT SET ALLOW_ID_TOKEN = true is set on the account.)

Every invocation completes the browser auth and then aborts:

$ snow sql -c oauth-conn -q "select 1"
...
An unexpected exception occurred. Use --debug option to see the traceback. Exception message:

(1783, 'CredWrite', 'The stub received bad data')

Since nothing was cached, the next invocation opens the browser again, and crashes again. The feature is effectively unusable for OAuth on Windows.

The cause is a hard limit in the Windows Credential Manager: CRED_MAX_CREDENTIAL_BLOB_SIZE is 2560 bytes, and keyring stores the blob as UTF-16, so anything over 1280 characters fails CredWrite with error 1783. My OAuth access token is ~1580 characters (~3160 bytes). The externalbrowser ID_TOKEN is only ~350 characters, which is why externalbrowser caching works fine on Windows and this only bites OAuth (and presumably any IdP that issues large JWTs). Same underlying limit as jaraco/keyring#355, python-poetry/poetry#6597, danieljoos/wincred#18.

The reason it crashes the whole command rather than just skipping the cache is an exception-type mismatch in KeyringTokenCache.store:

except keyring.errors.KeyringError as ke:
    self.logger.error("Could not store id_token to keyring, %s", str(ke))

WinVaultKeyring doesn't raise KeyringError here — the failed CredWrite surfaces as pywintypes.error (from win32ctypes.pywin32.pywintypes when pywin32-ctypes is installed, which keyring prefers), and that class derives from plain Exception:

>>> from keyring.backends.Windows import pywintypes
>>> import keyring.errors
>>> issubclass(pywintypes.error, keyring.errors.KeyringError)
False

So the except clause is dead code for this failure mode and the exception propagates out of the auth flow.

Minimal repro that needs no Snowflake account (Windows only):

import keyring
from keyring.backends.Windows import WinVaultKeyring
from snowflake.connector.token_cache import KeyringTokenCache, TokenKey, TokenType

keyring.set_keyring(WinVaultKeyring())
cache = KeyringTokenCache()
key = TokenKey("TESTUSER", "TEST.EXAMPLE.COM", TokenType.OAUTH_ACCESS_TOKEN)
cache.store(key, "x" * 1583)   # raises pywintypes.error (1783, 'CredWrite', ...)

With "x" * 350 (roughly ID_TOKEN size) the same call succeeds.

What did you expect to see?

A failed cache write should never abort a connection that has already authenticated successfully. store() should catch the backend's real exception types (OSError / pywintypes.error, not just KeyringError) and degrade to a no-op with a visible warning.
2. Ideally, tokens larger than the Credential Manager limit should still be cached ; either by chunking across multiple credential entries (the approach suggested in jaraco/keyring#355) or by falling back to a file-based cache on Windows. Failing that, a clear warning ("token too large for Windows Credential Manager, caching disabled") would at least tell users why they keep getting browser prompts.

Can you set logging to DEBUG and collect the logs?
import logging
import os

for logger_name in ('snowflake.connector',):
    logger = logging.getLogger(logger_name)
    logger.setLevel(logging.DEBUG)
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    ch.setFormatter(logging.Formatter('%(asctime)s - %(threadName)s %(filename)s:%(lineno)d - %(funcName)s() - %(levelname)s - %(message)s'))
    logger.addHandler(ch)

logs from DEBUG:

python: 3.13.14 (tags/v3.13.14:fd17997, Jun 10 2026, 13:03:48) [MSC v.1944 64 bit (AMD64)]
platform: Windows-11-10.0.26200-SP0
keyring backend: <class 'keyring.backends.Windows.WinVaultKeyring'>
issubclass(pywintypes.error, KeyringError): False

--- store of 350-char token (ID_TOKEN-sized) ---
retrieved: 350 chars

--- store of 1583-char token (OAuth-sized), expecting CredWrite 1783 ---
Traceback (most recent call last):
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\win32ctypes\pywin32\pywintypes.py", line 36, in pywin32error
    yield
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\win32ctypes\pywin32\win32cred.py", line 35, in CredWrite
    _authentication._CredWrite(c_pcreds, 0)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\win32ctypes\core\cffi\_authentication.py", line 155, in _CredWrite
    return check_false(
        dlls.advapi32.CredWriteW(Credential, Flags), u'CredWrite')
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\win32ctypes\core\cffi\_util.py", line 78, in __call__
    self._raise_error(function_name)
    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\win32ctypes\core\cffi\_util.py", line 89, in _raise_error
    raise exception
OSError: [WinError 1783] El fragmento ha recibido datos incorrectos

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\dev\UEFA\datacatalogue-api-tool\scripts\collect_credwrite_debug_logs.py", line 52, in <module>
    cache.store(key, "x" * 1583)  # unhandled traceback expected here
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\snowflake\connector\token_cache.py", line 372, in store
    keyring.set_password(
    ~~~~~~~~~~~~~~~~~~~~^
        key.string_key(),
        ^^^^^^^^^^^^^^^^^
        key.user.upper(),
        ^^^^^^^^^^^^^^^^^
        token,
        ^^^^^^
    )
    ^
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\keyring\core.py", line 70, in set_password
    get_keyring().set_password(service_name, username, password)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\keyring\backend.py", line 60, in wrapper
    return orig(self, system, username, *args, **kwargs)
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\keyring\backends\Windows.py", line 134, in set_password
    self._set_password(service, username, str(password))
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\keyring\backends\Windows.py", line 145, in _set_password
    win32cred.CredWrite(credential, 0)
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\win32ctypes\pywin32\win32cred.py", line 34, in CredWrite
    with _pywin32error():
         ~~~~~~~~~~~~~^^
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.13_3.13.3824.0_x64__qbz5n2kfra8p0\Lib\contextlib.py", line 162, in __exit__
    self.gen.throw(value)
    ~~~~~~~~~~~~~~^^^^^^^
  File "C:\Users\carlos.alemany\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\win32ctypes\pywin32\pywintypes.py", line 40, in pywin32error
    raise error(exception.winerror, exception.function, exception.strerror)
win32ctypes.pywin32.pywintypes.error: (1783, 'CredWrite', 'El fragmento ha recibido datos incorrectos')

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.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.