Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Install issue]: type object 'CreateCollection' has no attribute 'model_validate' during Create Index #2137

Open
zhou9110 opened this issue May 6, 2024 · 3 comments · May be fixed by #2119 or #2229
Labels
installation trouble trouble building or installing chroma

Comments

@zhou9110
Copy link

zhou9110 commented May 6, 2024

What happened?

After installed ChromaDB and run chroma run, it throws an error when I try to create a new index using the NodeJS client.

The reason I find out is because the version of pydantic is too old on my machine.
Mine was 1.10.12, and upgrading the library to the latest version (2.7.1) solves this issue.

pip install pydantic --upgrade

It seems the version in the requirement.txt is pydantic>=1.9 so it doesn't upgrade the library automatically during install, should the version number gets bumped?
Reference:

pydantic>=1.9

The code that throws the error (model_validate does not exist on 1.10):

create = CreateCollection.model_validate(orjson.loads(raw_body))

Versions

Chroma v0.5.0, Python 3.9.13, MacOS 14.4.1

Relevant log output

ERROR:    [06-05-2024 22:51:40] type object 'CreateCollection' has no attribute 'model_validate'
Traceback (most recent call last):
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/anyio/streams/memory.py", line 81, in receive
    return self.receive_nowait()
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/anyio/streams/memory.py", line 76, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/middleware/base.py", line 159, in call_next
    message = await recv_stream.receive()
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/anyio/streams/memory.py", line 101, in receive
    raise EndOfStream
anyio.EndOfStream

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/chromadb/server/fastapi/__init__.py", line 78, in catch_exceptions_middleware
    return await call_next(request)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/chromadb/server/fastapi/__init__.py", line 92, in check_http_version_middleware
    return await call_next(request)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 65, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/routing.py", line 297, in handle
    await self.app(scope, receive, send)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/routing.py", line 77, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/starlette/routing.py", line 72, in app
    response = await func(request)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/fastapi/routing.py", line 278, in app
    raw_response = await run_endpoint_function(
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
    return await dependant.call(**values)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/chromadb/telemetry/opentelemetry/__init__.py", line 130, in wrapper
    return await f(*args, **kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/chromadb/server/fastapi/__init__.py", line 630, in create_collection
    await to_thread.run_sync(
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/anyio/to_thread.py", line 28, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(func, *args, cancellable=cancellable,
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/anyio/_backends/_asyncio.py", line 818, in run_sync_in_worker_thread
    return await future
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/anyio/_backends/_asyncio.py", line 754, in run
    result = context.run(func, *args)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/chromadb/server/fastapi/__init__.py", line 606, in process_create_collection
    create = CreateCollection.model_validate(orjson.loads(raw_body))
AttributeError: type object 'CreateCollection' has no attribute 'model_validate'
INFO:     [06-05-2024 22:51:40] ::1:53570 - "POST /api/v1/collections?tenant=default_tenant&database=default_database HTTP/1.1" 500
@zhou9110 zhou9110 added the installation trouble trouble building or installing chroma label May 6, 2024
@HammadB
Copy link
Collaborator

HammadB commented May 9, 2024

This is a good point - @tazarov should we bump the version?

@tazarov
Copy link
Contributor

tazarov commented May 9, 2024

Pydantic 1.x also has similar function to so maybe we can implement an adapter that is version-aware function to keep backward compatibility.

We've added the orjson serialization in 0.5.0 and so far @zhou9110 is the first to notice which leads me to believe that not so many people are running pydantic <2.x. Maybe bumping the pydantic range >=2.0 and ditching 1.x as part of the 0.5.x versions can be an OK approach.

However if we go 2.x route we may want to also add pydantic-settings package and refactor the config (can be done in a separate PR).

@tazarov
Copy link
Contributor

tazarov commented May 11, 2024

looking at pydantic-settings package I can see that it basically requires pydantic > 2.7
https://github.com/pydantic/pydantic-settings/blob/6d25cee4bb7a6db592ca0da123c53f3d775cd1e1/pyproject.toml#L43

Using pedantic-settings as a package dependency, we're effectively forcing a pydantic>2.0 upgrade, which in @zhou9110's and other's cases might be a breaking change.

Another interesting aspect is our fastapi dep fastapi>=0.95.2, which translates:

https://github.com/tiangolo/fastapi/blob/c81e136d75f5ac4252df740b35551cf2afb4c7f1/pyproject.toml#L45

The above will cause some dependency resolution issues with older fastapi versions.

In the end, it will be a trade-off and a bit of a jerk move to force users to upgrade their deps which may come from other dependencies.

Bottom line:

pydantic>2.0 with pydantic-settings

  • pro: makes the code a bit cleaner as we'll remove all the pydantic 1.x compatibility logic
  • pro: allows us to bump fastapi
  • con: we add an extra dependency pydantic-settings
  • con: forces users to upgrade to pydantic>2.0
  • con: there are possible paths that lead to unreconcilable dependency conflicts and breaking changes

support for both versions

  • pro: we don't have to add pydantic-settings as direct dependency, but in case it is there we can use it
  • pro: no breaking changes for users
  • con: add more boilerplate code to support both versions that need to be maintained and tested
  • con: our tests always run on 2.x so it properly testing with older version requires additional CI with little gain, but it will help us avoid the above error

@HammadB, any strong opinion on which option to go for?

@tazarov tazarov linked a pull request May 11, 2024 that will close this issue
4 tasks
@tazarov tazarov linked a pull request May 11, 2024 that will close this issue
4 tasks
tazarov added a commit that referenced this issue May 20, 2024
@tazarov tazarov linked a pull request May 20, 2024 that will close this issue
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
installation trouble trouble building or installing chroma
Projects
None yet
3 participants