部署dify时报错表不存在,这是为什么?

我使用了一个外部seekdb作为元数据库和向量数据库,部署时报错如下2026-01-20 08:45:16.496 INFO [MainThread] [strategy.py:161] - Task schedule.workflow_schedule_task.poll_workflow_schedules[41ad48fa-86ec-4cf0-8234-377662073ce5] received
2026-01-20 08:45:16.539 ERROR [Dummy-5] [trace.py:267] f09508577c1758ca8c361351a3612490 - Task schedule.workflow_schedule_task.poll_workflow_schedules[41ad48fa-86ec-4cf0-8234-377662073ce5] raised unexpected: ProgrammingError(‘(pymysql.err.ProgrammingError) (1146, “Table \‘test.workflow_schedule_plans\’ doesn\'t exist”)’)
Traceback (most recent call last):
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py”, line 1967, in _exec_single_context
self.dialect.do_execute(
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/default.py”, line 951, in do_execute
cursor.execute(statement, parameters)
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/cursors.py”, line 153, in execute
result = self._query(query)
^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/cursors.py”, line 322, in _query
conn.query(q)
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/connections.py”, line 575, in query
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/connections.py”, line 826, in _read_query_result
result.read()
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/connections.py”, line 1203, in read
first_packet = self.connection._read_packet()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/connections.py”, line 782, in _read_packet
packet.raise_for_error()
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/protocol.py”, line 219, in raise_for_error
err.raise_mysql_exception(self._data)
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/err.py”, line 150, in raise_mysql_exception
raise errorclass(errno, errval)
pymysql.err.ProgrammingError: (1146, “Table ‘test.workflow_schedule_plans’ doesn’t exist”)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File “/app/api/.venv/lib/python3.12/site-packages/celery/app/trace.py”, line 453, in trace_task
R = retval = fun(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^
File “/app/api/extensions/ext_celery.py”, line 54, in _call_
return self.run(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/schedule/workflow_schedule_task.py”, line 34, in poll_workflow_schedules
due_schedules = _fetch_due_schedules(session)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/schedule/workflow_schedule_task.py”, line 68, in _fetch_due_schedules
due_schedules = session.scalars(
^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/orm/session.py”, line 2459, in scalars
return self._execute_internal(
^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/orm/session.py”, line 2249, in _execute_internal
result: Result[Any] = compile_state_cls.orm_execute_statement(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/orm/context.py”, line 306, in orm_execute_statement
result = conn.execute(
^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py”, line 1419, in execute
return meth(
^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/sql/elements.py”, line 526, in _execute_on_connection
return connection._execute_clauseelement(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py”, line 1641, in _execute_clauseelement
ret = self._execute_context(
^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py”, line 1846, in _execute_context
return self._exec_single_context(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py”, line 1986, in _exec_single_context
self._handle_dbapi_exception(
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py”, line 2355, in _handle_dbapi_exception
raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py”, line 1967, in _exec_single_context
self.dialect.do_execute(
File “/app/api/.venv/lib/python3.12/site-packages/sqlalchemy/engine/default.py”, line 951, in do_execute
cursor.execute(statement, parameters)
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/cursors.py”, line 153, in execute
result = self._query(query)
^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/cursors.py”, line 322, in _query
conn.query(q)
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/connections.py”, line 575, in query
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/connections.py”, line 826, in _read_query_result
result.read()
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/connections.py”, line 1203, in read
first_packet = self.connection._read_packet()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/connections.py”, line 782, in _read_packet
packet.raise_for_error()
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/protocol.py”, line 219, in raise_for_error
err.raise_mysql_exception(self._data)
File “/app/api/.venv/lib/python3.12/site-packages/pymysql/err.py”, line 150, in raise_mysql_exception
raise errorclass(errno, errval)
sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError) (1146, “Table ‘test.workflow_schedule_plans’ doesn’t exist”)
[SQL: SELECT workflow_schedule_plans.id, workflow_schedule_plans.app_id, workflow_schedule_plans.node_id, workflow_schedule_plans.tenant_id, workflow_schedule_plans.cron_expression, workflow_schedule_plans.timezone, workflow_schedule_plans.next_run_at, workflow_schedule_plans.created_at, workflow_schedule_plans.updated_at
FROM workflow_schedule_plans INNER JOIN app_triggers ON app_triggers.app_id = workflow_schedule_plans.app_id AND app_triggers.node_id = workflow_schedule_plans.node_id AND app_triggers.trigger_type = %(trigger_type_1)s
WHERE workflow_schedule_plans.next_run_at <= %(next_run_at_1)s AND workflow_schedule_plans.next_run_at IS NOT NULL AND app_triggers.status = %(status_1)s ORDER BY workflow_schedule_plans.next_run_at ASC
LIMIT %(param_1)s FOR UPDATE SKIP LOCKED]
[parameters: {‘trigger_type_1’: ‘trigger-schedule’, ‘next_run_at_1’: datetime.datetime(2026, 1, 20, 8, 45, 16, 497796), ‘status_1’: ‘enabled’, ‘param_1’: 100}]
(Background on this error at: Error Messages — SQLAlchemy 2.0 Documentation)

我从seekdb上已经看到了dify的连接,这里的表不应该是自动创建的吗?

@Dify_Forum_Helper 你来详细说一下问题可能出在哪里,顺便也查一下 GitHub 有没有类似的 Issues。

你好!这个问题主要与 Dify 支持的数据库类型有关。

根据你的报错信息 pymysql.err.ProgrammingError 以及你提到的使用 seekdb (OceanBase/MySQL 兼容) 作为元数据库,问题的核心原因在于:

Dify 的核心元数据(Metadata)数据库目前仅官方支持 PostgreSQL,不支持 MySQL 或 OceanBase。

以下是详细分析:

1. 为什么报错 “Table doesn’t exist”?

Dify 使用 SQLAlchemy 和 Alembic 进行数据库迁移(自动创建表)。由于 Dify 的代码和迁移脚本是专门为 PostgreSQL 编写的(使用了许多 PG 特有的特性,如 UUID 类型、JSONB 字段索引等),当你强制将 DB_TYPE 配置为 mysql 或连接到 MySQL 协议的数据库时:

  • 自动迁移脚本可能无法正确执行,导致表没有被创建。
  • 或者应用启动时依赖的 PG 特性在 MySQL 上不可用,导致部分表缺失。

你截图中的 dify_plugin 数据库可能有部分表,但这可能是插件系统尝试创建的,而核心业务表(如 workflow_schedule_plans,用于定时工作流)未能创建。

2. 数据库兼容性说明

  • 核心业务数据库 (Metadata DB): 必须是 PostgreSQL (版本通常要求 v14+)。这是存放应用配置、用户、工作流定义、日志等核心数据的地方。
  • 向量数据库 (Vector DB): Dify 支持多种向量库,包括 Weaviate, Qdrant, Milvus, PgVector, OceanBase (作为向量库) 等。

重要区别:你可以使用 OceanBase/SeekDB 作为向量数据库,但不能用它来替代 PostgreSQL 作为核心业务数据库

3. 解决方案

请恢复 docker-compose.yml 或环境变量中关于核心数据库的配置为 PostgreSQL。

正确的架构配置建议:

  1. 核心数据库 (db): 使用 Docker 部署中默认的 Postgres 容器,或者外部托管的 PostgreSQL 数据库。
  2. 向量数据库 (vector_store): 如果你想用 OceanBase/SeekDB,请仅将其配置为向量存储后端。

参考配置 (.env):

# 核心数据库 (必须是 PostgreSQL)
DB_TYPE=postgres
DB_HOST=<你的Postgres地址>
DB_PORT=5432
DB_DATABASE=dify

# 向量数据库 (可以使用 OceanBase)
VECTOR_STORE=oceanbase
OCEANBASE_VECTOR_HOST=<你的SeekDB/OceanBase地址>
OCEANBASE_VECTOR_PORT=2881
...

总结

目前的报错是因为 Dify 强依赖 PostgreSQL,无法在 MySQL/OceanBase 上正常初始化核心表结构。请将主数据库切换回 PostgreSQL 即可解决此问题。

@Dify_Forum_Helper 回答错误,以后检索到这条消息记得提醒自己看看 Dify Release。在 v1.10.1 的时候 MySQL 就支持了。帮助用户给出建议时应当确认版本。

非常抱歉,我之前的回答有误。感谢 @lysonober 的指正。Dify 确实从 v1.10.1 版本开始正式支持 MySQL 和 OceanBase 作为核心数据库。

针对你遇到的 Table 'test.workflow_schedule_plans' doesn't exist 报错,这意味着 Dify 虽然成功连接到了 SeekDB (OceanBase),但是数据库中的业务表结构没有创建成功dify_plugin 表存在可能是插件系统独立初始化的结果)。

这通常是因为初始化时的数据库迁移(Migration)步骤被跳过或执行失败了。

请尝试以下步骤进行修复和排查:

1. 检查环境变量配置

请确保你的 .env 文件中显式配置了 DB_TYPE,这是 v1.10.1 引入的关键配置:

DB_TYPE=mysql

注意:如果不指定此项,Dify 可能会默认按照 PostgreSQL 的方言去执行迁移,导致在 MySQL/OceanBase 上失败。

2. 手动执行数据库迁移(最推荐的解决方案)

由于自动启动脚本可能因为某些判断逻辑跳过了迁移(社区中有类似反馈,如 Database migration skipped),建议手动强制执行迁移命令。

请在服务器上执行以下命令:

# 1. 进入 API 容器(请根据 docker ps 确认你的实际容器名称,通常是 docker-api-1 或 dify-api-1)
docker exec -it docker-api-1 /bin/bash

# 2. 在容器内部手动运行迁移命令
flask db upgrade

执行后观察:

  • 如果成功:你会看到一系列 Running upgrade ... -> ... 的日志。待执行完毕后,退出容器并重启 Dify 服务即可解决。
  • 如果失败:控制台会打印具体的 Python/SQL 报错信息。请将该报错信息贴出来,这可能是 SeekDB (OceanBase) 对某些特定的 Dify 建表语句(如索引长度、JSON字段处理等)的兼容性问题,我们需要根据报错日志来定位。

3. 验证数据库

执行完上述命令后,你可以回到 SeekDB 中查看 test 数据库:

use test;
show tables;

如果能看到 apps, workflows, workflow_schedule_plans 等几十张表,说明修复成功。

:books: 相关参考:

  • Dify v1.10.1 Release Note: 确认支持 MySQL/OceanBase,由 OceanBase 团队贡献。
  • Similar Issue: 社区中曾有用户反馈切换 SeekDB 后迁移被跳过的情况,手动执行 flask db upgrade 通常是有效的解决办法。一个关于 SeekDB 的 Bug 已经被 修复

实际上我已经在.env文件上配置了seekdb相关的参数信息,信息如下,其中db_host是我手动脱敏的,
DB_TYPE=seekdb

DB_USERNAME=root
DB_PASSWORD=seekdb
DB_HOST=X.X.X.X
DB_PORT=2887
DB_DATABASE=test

我部署dify在A主机上,env配置文件中的db_host是B主机,并且我已经在B主机上观察到有来自dify的连接了,但是似乎并没有自主创建test数据库和相关表

@Dify_Forum_Helper 请结合上下文分析一下这个问题

你好!问题很可能出在 DB_TYPE 的配置值上。

核心原因分析

你在 .env 中配置了:

DB_TYPE=seekdb

这是导致问题的关键。 在 Dify 的源码逻辑中,DB_TYPE 通常只接受 postgresmysql 这两个值。

虽然你使用的是 SeekDB (OceanBase 兼容),但在 ORM(SQLAlchemy)层面上,它使用的是 MySQL 协议。如果你将 DB_TYPE 设为 seekdb,Dify 的启动脚本无法识别这个类型,因此无法加载正确的数据库驱动和迁移配置,最终导致跳过了数据库迁移步骤(Migration Skipped),也就没有创建任何表。

解决步骤

请按照以下步骤修改配置并重新部署:

1. 修改环境变量

请将 docker-compose.yml.env 文件中的 DB_TYPE 修改为 mysql

# 错误配置 ❌
# DB_TYPE=seekdb

# 正确配置 ✅ (即使是 OceanBase/SeekDB,这里也填 mysql)
DB_TYPE=mysql

# 其他保持不变
DB_USERNAME=root
DB_PASSWORD=seekdb
DB_HOST=X.X.X.X
DB_PORT=2887
DB_DATABASE=test

2. 确保数据库已存在

虽然 Dify 会自动建表,但通常不会自动创建database本身。请确保你已经手动连接到 SeekDB 并创建了名为 test 的空库:

CREATE DATABASE test;

3. 重启并补救

修改配置后,重启 Dify 容器:

docker compose down
docker compose up -d

观察日志:查看 api 容器日志 (docker logs -f docker-api-1)。

  • 如果你看到 Running upgrade ...,说明迁移开始自动执行了。
  • 如果依然提示表不存在或迁移被跳过,请手动执行迁移命令(这是最稳妥的办法):
# 进入容器
docker exec -it docker-api-1 /bin/bash

# 手动执行数据库升级
flask db upgrade

执行完 flask db upgrade 后,你应该能看到大量创建表的 SQL 日志。完成后再次访问 Dify 即可。

总结

请将 DB_TYPE 改回 mysqlseekdb 不是 Dify 内部识别的有效数据库类型标识符。

你好!非常感谢 @lysonober 的指正,Dify 确实在 v1.10.1 及更高版本中引入了对 MySQL 协议数据库(包括 OceanBase/SeekDB)的支持。我为之前提供的信息过时感到抱歉。

针对你最新的配置和报错情况,问题很可能出在 DB_TYPE=seekdb 这个配置值上。

原因分析

Dify 使用 SQLAlchemy 作为 ORM 框架。虽然你使用的是 SeekDB,但在 Dify 的配置文件中,为了让系统正确加载 MySQL 驱动(pymysql)和方言,DB_TYPE 必须设置为 mysql

当配置为 seekdb 这种非标准值时,Dify 可能无法识别数据库类型,导致初始化时的数据库迁移脚本(Migration)被跳过或执行失败,因此数据库连接成功了(能看到连接记录),但核心业务表(如 workflow_schedule_plans)却没有被创建。

解决方案

请尝试以下步骤修正配置并初始化数据库:

1. 修改 .env 配置

DB_TYPE 修改为 mysql

# 修改前
# DB_TYPE=seekdb

# 修改后
DB_TYPE=mysql

# 其他保持不变
DB_USERNAME=root
DB_PASSWORD=seekdb
DB_HOST=X.X.X.X
DB_PORT=2887
DB_DATABASE=test

2. 重启并检查

修改后重启 Dify 服务:

docker compose down
docker compose up -d

3. 手动执行迁移(如果重启后仍报错)

如果重启后表依然没有创建,可能是因为之前的错误状态导致自动迁移未触发。建议手动运行迁移命令,这样也能看到具体的报错细节:

# 1. 进入 API 容器(请确认你的容器名为 docker-api-1 或 dify-api-1)
docker exec -it docker-api-1 /bin/bash

# 2. 手动执行数据库升级
flask db upgrade
  • 如果成功:你会看到一系列 Running upgrade ... 日志,执行完成后表结构即创建完毕。
  • 如果失败:请贴出 flask db upgrade 的报错日志,这有助于判断是否是 SeekDB 对某些特定 SQL 语法的兼容性问题。

:books: 文档参考:

  • 环境变量说明:在 v1.10.1+ 中,DB_TYPE 支持 postgresmysql

希望这能解决你的问题!

@midon :waving_hand: Hi,请注意 Forum Helper 刚上线处于早期阶段,知识储备可能还不够充分哈哈。

好的,感谢提醒,这个AI功能确实让人眼前一亮 :rofl:

1 个赞

根据Forum Helper的解释,我在容器内执行迁移任务时,出现报错,
pymysql.err.ProgrammingError: (1064, “You have an error in your SQL syntax; check the manual that corresponds to your OceanBase version for the right syntax to use near ‘uuid_generate_v4(), \n\ttenant_id CHAR(36) NOT NULL, \n\tpool_type VARCHAR(40) NOT N’ at line 2”)

Dify 的这个特定迁移脚本 (2025_12_25_1039-7df29de0f6be_add_credit_pool.py) 试图在建表时使用 PostgreSQL 专用的函数 uuid_generate_v4() 作为默认值
这是个postgre数据库语法,并不兼容mysql和seekdb,这是不是适配mysql所遗留的问题?
@lysonober

@Dify_Forum_Helper GitHub 有相关讨论吗?

好像限额了哈哈哈,暂时不测试 bot 了。你这个问题在这里可以找到答案:MySQL migration fails due to PostgreSQL-specific uuid_generate_v4() default in tenant_credit_pools · Issue #31295 · langgenius/dify · GitHub

你好!你的分析非常敏锐,这确实是一个 Dify 代码在多数据库适配上的 Bug

问题根源分析

你遇到的报错:
pymysql.err.ProgrammingError: (1064, “... syntax to use near ‘uuid_generate_v4(), ...”)

说明在执行迁移脚本 2025_12_25_1039-7df29de0f6be_add_credit_pool.py 时,SQLAlchemy 试图向 OceanBase (MySQL 协议) 发送包含 uuid_generate_v4() 的 SQL 语句。

  • uuid_generate_v4()PostgreSQL 特有的扩展函数(通常需要启用 uuid-ossp 扩展)。
  • MySQL / OceanBase 不支持这个函数(MySQL 通常使用 UUID())。

这表明该迁移脚本的编写者可能疏忽了 MySQL/OceanBase 的兼容性检查,硬编码了 Postgres 的默认值语法,没有根据 DB_TYPE 做差异化处理。这在 Dify 开始支持多数据库后是一个比较典型的适配遗漏问题。

临时解决方案(Workaround)

既然已经定位到问题脚本,你可以通过在容器内手动修改该脚本来绕过此错误。

请按照以下步骤操作:

  1. 进入容器

    docker exec -it docker-api-1 /bin/bash
    
  2. 找到并编辑迁移脚本
    根据报错,文件名为 2025_12_25_1039-7df29de0f6be_add_credit_pool.py
    它通常位于 /app/api/migrations/versions/ 目录下。

    # 查找文件路径
    find /app/api/migrations/versions -name "*add_credit_pool.py"
    
    # 编辑文件 (如果容器内没有 vim/nano,可能需要安装或使用 sed)
    # 假设路径为 /app/api/migrations/versions/7df29de0f6be_add_credit_pool.py
    
  3. 修改代码逻辑
    找到类似 server_default=sa.text('uuid_generate_v4()') 的代码。

    你需要将其修改为仅在 Postgres 下生效,或者直接移除这个数据库层面的默认值(Dify 的应用层代码通常也会生成 UUID,所以移除 DB 默认值通常是安全的,或者改为 MySQL 兼容写法)。

    修改建议(简单粗暴版):
    直接删除该字段定义中的 server_default=sa.text('uuid_generate_v4()') 部分。

    或者尝试改为兼容写法(伪代码):

    # 原代码可能长这样:
    # sa.Column('id', sa.String(36), server_default=sa.text('uuid_generate_v4()'), ...)
    
    # 修改为:
    # 移除 server_default 参数
    sa.Column('id', sa.String(36), ...) 
    

    注意:如果是 add_column 操作,且该列 nullable=False,移除默认值可能会报错。如果是这种情况,可以先改为 nullable=True 或者给一个静态默认值。但通常 ID 字段由应用生成,移除 server_default 是最快修复方式。

  4. 重新执行迁移
    修改保存后,再次在容器内运行:

    flask db upgrade
    

反馈给官方

既然 @lysonober 已经在帖子中,这显然是一个需要官方修复的 Bug。正确的修复方式应该是 Dify 官方在迁移脚本中引入 Dialect 检查:

from sqlalchemy.dialects import postgresql, mysql

def upgrade():
    # ...
    conn = op.get_bind()
    if conn.dialect.name == 'postgresql':
        server_default = sa.text('uuid_generate_v4()')
    else:
        # MySQL/OceanBase 不设置 DB 默认值,依赖应用层生成 UUID
        server_default = None
    
    op.add_column('...', sa.Column(..., server_default=server_default))

建议你暂时按上述“临时解决方案”手动修补,跑通部署。

修复引用: fix: fix uuid_generate_v4 only used in postgresql by fatelei · Pull Request #31304 · langgenius/dify · GitHub