chroma-core / chroma

the AI-native open-source embedding database
https://www.trychroma.com/
Apache License 2.0
14.72k stars 1.23k forks source link

[Bug] UnicodeDecodeError during Basic Authentication Setup in Docker #2855

Closed JaylenC closed 4 days ago

JaylenC commented 4 days ago

What happened?

Hi,

I am trying to set up Basic Authentication, but unfortunately, I keep encountering the following error:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

As a result, the Docker container crashes.

Could you please help me resolve this issue? I’m unsure what might be causing the problem and would greatly appreciate any guidance.

Thank you in advance for your support!

Best regards,

Versions

chromadb/chroma: 0.5.7

Relevant log output

entire log of the docker:
Chroma-DB  | Starting 'uvicorn chromadb.app:app' with args: --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config chromadb/log_config.yml --timeout-keep-alive 30
Chroma-DB  | WARNING:  [25-09-2024 13:37:50] chroma_server_nofile is set to 65536, but this is less than current soft limit of 1048576. chroma_server_nofile will not be set.
Chroma-DB  | DEBUG:    [25-09-2024 13:37:50] Starting component System
Chroma-DB  | DEBUG:    [25-09-2024 13:37:50] Starting component OpenTelemetryClient
Chroma-DB  | DEBUG:    [25-09-2024 13:37:50] Starting component SqliteDB
Chroma-DB  | DEBUG:    [25-09-2024 13:37:50] Starting component QuotaEnforcer
Chroma-DB  | DEBUG:    [25-09-2024 13:37:50] Starting component Posthog
Chroma-DB  | DEBUG:    [25-09-2024 13:37:50] Starting component LocalSegmentManager
Chroma-DB  | DEBUG:    [25-09-2024 13:37:50] Starting component SegmentAPI
Chroma-DB  | Traceback (most recent call last):
Chroma-DB  |   File "/usr/local/bin/uvicorn", line 8, in <module>
Chroma-DB  |     sys.exit(main())
Chroma-DB  |              ^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1157, in __call__
Chroma-DB  |     return self.main(*args, **kwargs)
Chroma-DB  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1078, in main
Chroma-DB  |     rv = self.invoke(ctx)
Chroma-DB  |          ^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1434, in invoke
Chroma-DB  |     return ctx.invoke(self.callback, **ctx.params)
Chroma-DB  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/click/core.py", line 783, in invoke
Chroma-DB  |     return __callback(*args, **kwargs)
Chroma-DB  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 410, in main
Chroma-DB  |     run(
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 577, in run
Chroma-DB  |     server.run()
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 65, in run
Chroma-DB  |     return asyncio.run(self.serve(sockets=sockets))
Chroma-DB  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
Chroma-DB  |     return runner.run(main)
Chroma-DB  |            ^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
Chroma-DB  |     return self._loop.run_until_complete(task)
Chroma-DB  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "uvloop/loop.pyx", line 1517, in uvloop.loop.Loop.run_until_complete
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 69, in serve
Chroma-DB  |     await self._serve(sockets)
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 76, in _serve
Chroma-DB  |     config.load()
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/uvicorn/config.py", line 434, in load
Chroma-DB  |     self.loaded_app = import_from_string(self.app)
Chroma-DB  |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/site-packages/uvicorn/importer.py", line 19, in import_from_string
Chroma-DB  |     module = importlib.import_module(module_str)
Chroma-DB  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/usr/local/lib/python3.11/importlib/__init__.py", line 126, in import_module
Chroma-DB  |     return _bootstrap._gcd_import(name[level:], package, level)
Chroma-DB  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
Chroma-DB  |   File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
Chroma-DB  |   File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
Chroma-DB  |   File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
Chroma-DB  |   File "<frozen importlib._bootstrap_external>", line 940, in exec_module
Chroma-DB  |   File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
Chroma-DB  |   File "/chroma/chromadb/app.py", line 6, in <module>
Chroma-DB  |     server = FastAPI(settings)
Chroma-DB  |              ^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/chroma/chromadb/server/fastapi/__init__.py", line 185, in __init__
Chroma-DB  |     self.authn_provider = self._system.require(ServerAuthenticationProvider)
Chroma-DB  |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/chroma/chromadb/config.py", line 297, in require
Chroma-DB  |     inst = self._system.instance(type)
Chroma-DB  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/chroma/chromadb/config.py", line 404, in instance
Chroma-DB  |     impl = type(self)
Chroma-DB  |            ^^^^^^^^^^
Chroma-DB  |   File "/chroma/chromadb/auth/basic_authn/__init__.py", line 75, in __init__
Chroma-DB  |     creds = self.read_creds_or_creds_file()
Chroma-DB  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Chroma-DB  |   File "/chroma/chromadb/auth/__init__.py", line 125, in read_creds_or_creds_file
Chroma-DB  |     return f.readlines()
Chroma-DB  |            ^^^^^^^^^^^^^
Chroma-DB  |   File "<frozen codecs>", line 322, in decode
Chroma-DB  | UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
Chroma-DB exited with code 0

docker-compse.yml file:
services:
  chromaDB:
    image: chromadb/chroma:0.5.7
    restart: unless-stopped
    container_name: 'Chroma-DB'
    volumes:
      - ./db:/chroma/chroma
      - ./server.htpasswd:/chroma/server.htpasswd
    environment:
      - IS_PERSISTENT=TRUE
      - PERSIST_DIRECTORY=/chroma/chroma
      - ANONYMIZED_TELEMETRY=FALSE
      - CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.basic_authn.BasicAuthenticationServerProvider
      - CHROMA_SERVER_AUTHN_CREDENTIALS_FILE=/chroma/server.htpasswd
    networks:
      - chroma-network
    ports:
      - "7000:8000"
networks:
  chroma-network:
   driver: bridge
   name: chroma-network
tazarov commented 4 days ago

hey @JaylenC, the issue you're facing is incorrectly created /chroma/server.htpasswd. The issue is usually observed if your hash is not bcrypt (currently we expect a bcrypt hashes in .htpasswd files). Have a look here - https://cookbook.chromadb.dev/security/auth/#basic-authentication (the gist is the -B flag(

JaylenC commented 4 days ago

hey @JaylenC, the issue you're facing is incorrectly created /chroma/server.htpasswd. The issue is usually observed if your hash is not bcrypt (currently we expect a bcrypt hashes in .htpasswd files). Have a look here - https://cookbook.chromadb.dev/security/auth/#basic-authentication (the gist is the -B flag(

Hello @tazarov , thank you very much for your response. I used the following code to create the hash:

docker run --rm --entrypoint htpasswd httpd:2 -Bbn admin admin > server.htpasswd

This can be found at https://docs.trychroma.com/deployment/auth. While the file was created correctly and its contents seemed to be correct, it did not work.

I then installed htpasswd and followed your suggested guide. That seems to have worked. However, now I keep getting the following error message when I try to test everything:

ValueError: Could not connect to tenant default_tenant. Are you sure it exists?

Unfortunately, I haven’t been able to figure out how to resolve this issue yet. Do you have any suggestions for solving this problem?

Thank you very much in advance,

tazarov commented 4 days ago

@JaylenC, can you share the full error stack?

Could not connect to tenant default_tenant. Are you sure it exists? is ambiguous and does not reveal the actual error which is usually printed up the stack. Did you see anything in server logs?

JaylenC commented 4 days ago

@JaylenC, can you share the full error stack?

Could not connect to tenant default_tenant. Are you sure it exists? is ambiguous and does not reveal the actual error which is usually printed up the stack. Did you see anything in server logs?

@tazarov Sure, sorry about that. Here you go:

Traceback (most recent call last):
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\api\base_http_client.py", line 99, in _raise_chroma_error
    resp.raise_for_status()
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\httpx\_models.py", line 763, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '403 Forbidden' for url 'http://localhost:7000/api/v1/tenants/default_tenant'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\api\client.py", line 371, in _validate_tenant_database
    self._admin_client.get_tenant(name=tenant)
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\api\client.py", line 415, in get_tenant
    return self._server.get_tenant(name=name)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\telemetry\opentelemetry\__init__.py", line 146, in wrapper
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\api\fastapi.py", line 137, in get_tenant
    resp_json = self._make_request("get", "/tenants/" + name)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\api\fastapi.py", line 87, in _make_request
    BaseHTTPClient._raise_chroma_error(response)
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\api\base_http_client.py", line 103, in _raise_chroma_error
    raise Exception(f"{resp.text} (trace ID: {trace_id})")
Exception: {"error":"AuthError","message":"Forbidden"} (trace ID: 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Headaway\Desktop\Studium\Bachelor\Code\Help-ITC-Chatbot\production\chroma-db\client.py", line 4, in <module>
    client = chromadb.HttpClient(host="localhost", port=7000,
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\__init__.py", line 204, in HttpClient
    return ClientCreator(tenant=tenant, database=database, settings=settings)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\api\client.py", line 61, in __init__
    self._validate_tenant_database(tenant=tenant, database=database)
  File "C:\Users\Headaway\AppData\Local\Programs\Python\Python312\Lib\site-packages\chromadb\api\client.py", line 380, in _validate_tenant_database
    raise ValueError(
ValueError: Could not connect to tenant default_tenant. Are you sure it exists?

Server logs:

Chroma-DB: ERROR:    [26-09-2024 10:27:27] BasicAuthenticationServerProvider.authenticate failed: AuthError('Invalid username or password')
Chroma-DB: INFO:     [26-09-2024 10:27:27] 172.18.0.1:49410 - "GET /api/v1/tenants/default_tenant HTTP/1.1" 403
Chroma-DB: WARNING:  [26-09-2024 10:48:28] Invalid HTTP request received.

I'm pretty sure I set the username and password correctly.

tazarov commented 4 days ago

yeah httpx.HTTPStatusError: Client error '403 Forbidden' for url 'http://localhost:7000/api/v1/tenants/default_tenant' is Auth error for sure.

But this time the htpasswd file seems to be ok.

Can you check with curl:

curl -v http://localhost:7000/api/v1/tenants/default_tenant -u <user>:<password>

Alternatively:

docker run --rm -v ./server.htpasswd:/server.htpasswd --entrypoint htpasswd httpd:2 -vb /server.htpasswd <user> <password>
JaylenC commented 4 days ago

Hi, I manually encoded and checked the password in the file again, and it seemed to be different from when the file was created. I then manually adjusted the hash in the file, and now everything seems to be working:

* Server auth using Basic with user 'user1'
> GET /api/v1/collections HTTP/1.1
> Host: localhost:7000
> Authorization: Basic dXNlcjE6YWRtaW4=
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Thu, 26 Sep 2024 11:21:23 GMT
< server: uvicorn
< content-length: 2
< content-type: application/json
< chroma-trace-id: 0
<
* Connection #0 to host localhost left intact

So, there was probably some error when creating the hash. I'm not exactly sure what went wrong. I also tried creating a file again, but that didn’t work properly.

Anyway, thank you for your help.