langgenius / dify

Dify is an open-source LLM app development platform. Dify's intuitive interface combines AI workflow, RAG pipeline, agent capabilities, model management, observability features and more, letting you quickly go from prototype to production.
https://dify.ai
Other
45.55k stars 6.41k forks source link

Instance <Provider at 0x7d21b5bcbd60> has a NULL identity key #7521

Open shengxiagit opened 3 weeks ago

shengxiagit commented 3 weeks ago

Self Checks

Dify version

v0.7.1

Cloud or Self Hosted

Self Hosted (Source)

Steps to reproduce

When I add a model voucher, an error message appears, like this:

·· sqlalchemy.orm.exc.FlushError: Instance <Provider at 0x7d21b5a12f80> has a NULL identity key. If this is an auto-generated value, check that the database table allows generation of new primary key values, and that the mapped Column object is configured to expect these generated values. Ensure also that this flush() is not occurring at an inappropriate time, such as within a load() event.

✔️ Expected Behavior

model provider add success

❌ Actual Behavior

2024-08-22 01:34:45,263.263 INFO [Dummy-1] [_client.py:1026] - HTTP Request: POST https://api.aigc369.com/v1/chat/completions "HTTP/1.1 200 OK"
2024-08-22 01:34:45,273.273 ERROR [Dummy-1] [app.py:838] - Exception on /console/api/workspaces/current/model-providers/openai [POST]
Traceback (most recent call last):
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/flask/app.py", line 880, in full_dispatch_request
    rv = self.dispatch_request()
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/flask/app.py", line 865, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/flask_restful/__init__.py", line 489, in wrapper
    resp = resource(*args, **kwargs)
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/flask/views.py", line 110, in view
    return current_app.ensure_sync(self.dispatch_request)(**kwargs)  # type: ignore[no-any-return]
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/flask_restful/__init__.py", line 604, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/opt/project/dify-api/api/controllers/console/setup.py", line 75, in decorated
    return view(*args, **kwargs)
  File "/opt/project/dify-api/api/libs/login.py", line 93, in decorated_view
    return current_app.ensure_sync(func)(*args, **kwargs)
  File "/opt/project/dify-api/api/controllers/console/wraps.py", line 22, in decorated
    return view(*args, **kwargs)
  File "/opt/project/dify-api/api/controllers/console/workspace/model_providers.py", line 112, in post
    model_provider_service.save_provider_credentials(
  File "/opt/project/dify-api/api/services/model_provider_service.py", line 157, in save_provider_credentials
    provider_configuration.add_or_update_custom_credentials(credentials)
  File "/opt/project/dify-api/api/core/entities/provider_configuration.py", line 245, in add_or_update_custom_credentials
    db.session.commit()
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/scoping.py", line 597, in commit
    return self._proxied.commit()
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2028, in commit
    trans.commit(_to_root=True)
  File "<string>", line 2, in commit
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/state_changes.py", line 139, in _go
    ret_value = fn(self, *arg, **kw)
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 1313, in commit
    self._prepare_impl()
  File "<string>", line 2, in _prepare_impl
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/state_changes.py", line 139, in _go
    ret_value = fn(self, *arg, **kw)
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 1288, in _prepare_impl
    self.session.flush()
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 4352, in flush
    self._flush(objects)
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 4487, in _flush
    with util.safe_reraise():
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
    raise exc_value.with_traceback(exc_tb)
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 4454, in _flush
    flush_context.finalize_flush_changes()
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/unitofwork.py", line 487, in finalize_flush_changes
    self.session._register_persistent(other)
  File "/opt/module/anaconda3/envs/dify-local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 3353, in _register_persistent
    raise exc.FlushError(
sqlalchemy.orm.exc.FlushError: Instance <Provider at 0x7d21b5a12f80> has a NULL identity key.  If this is an auto-generated value, check that the database table allows generation of new primary key values, and that the mapped Column object is configured to expect these generated values.  Ensure also that this flush() is not occurring at an inappropriate time, such as within a load() event.
dosubot[bot] commented 3 weeks ago

Hey @shengxiagit! I'm a bot designed to help you with bugs, questions, and becoming a contributor. I'm here to assist you while you wait for a human maintainer.

To resolve the "Instance <Provider at 0x7d21b5a12f80> has a NULL identity key" error when adding a model voucher in a self-hosted Dify v0.7.1 setup, ensure that the Provider instance has a valid identity key before it is added to the database. This typically involves setting the primary key or ensuring that the necessary fields are populated correctly.

Here is a snippet of code that shows how to ensure the Provider instance has a valid identity key:

from models.provider import Provider
from extensions.ext_database import db

class ProviderManager:
    # Other methods...

    def add_provider(self, tenant_id: str, provider_data: dict) -> Provider:
        """
        Add a new provider to the database.

        :param tenant_id: The tenant ID.
        :param provider_data: A dictionary containing provider data.
        :return: The created Provider instance.
        """
        # Create a new Provider instance
        new_provider = Provider(**provider_data)

        # Ensure the identity key is set (e.g., primary key)
        if not new_provider.id:
            new_provider.id = self.generate_unique_id()

        # Add the provider to the session and commit
        db.session.add(new_provider)
        try:
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            raise

        return new_provider

    def generate_unique_id(self) -> str:
        """
        Generate a unique ID for the provider.

        :return: A unique ID string.
        """
        # Implement your unique ID generation logic here
        return str(uuid.uuid4())

In this example, the add_provider method ensures that the Provider instance has a valid id before it is added to the database. The generate_unique_id method is a placeholder for your unique ID generation logic, which could be based on UUIDs or any other scheme suitable for your application [1].

Additionally, ensure that the Provider class's primary key is correctly defined and managed in the database schema. The id column should be defined as follows:

id = db.Column(StringUUID, server_default=db.text('uuid_generate_v4()'))

This column uses the StringUUID type and has a default value generated by the uuid_generate_v4() function, ensuring that each Provider instance has a unique identifier [2].

To continue talking to Dosu, mention @dosu.