sqlmodel: Optional[Dict[str, str]] field handle error, (sqlite3.InterfaceError) Error binding parameter 4 - probably unsupported type.

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the SQLModel documentation, with the integrated search.
  • I already searched in Google “How to X in SQLModel” and didn’t find any information.
  • I already read and followed all the tutorial in the docs and didn’t find an answer.
  • I already checked if it is not related to SQLModel but to Pydantic.
  • I already checked if it is not related to SQLModel but to SQLAlchemy.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

class TaskCreate(SQLModel):
    name: str
    report_id: UUID
    target: Optional[HttpUrl]
    version: str
    md5: Optional[Dict[str, str]]
    onsite: Optional[bool] = Field(default=False)
    envs: Optional[Dict[str, str]]

    # foreign key
    client_id: Optional[int] = Field(default=None, foreign_key="client.id")


@router.post("/", response_model=Task)
def create_tasks(
        *,
        db: Session = Depends(get_session),
        task_in: TaskCreate
):
    """
    Create a task.
    """
    db_task = Task.from_orm(task_in)
    db.add(db_task)
    db.commit()
    db.refresh(db_task)
    return db_task

Description

{
  "name": "task1",
  "report_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "target": "http://a.com",
  "version": "v1.0",
  "md5": {
    "app.zip": "1231231231231234"
  },
  "onsite": false,
  "envs": {
    "apache": "5.0"
  },
  "client_id": 0
}

In the docs, I’m trying to create task with the above data, but I find that it can’t be created with json embeded, leading to the following error:

INFO:     127.0.0.1:56340 - "POST /tasks/ HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/Users/m0nst3r/dev/py/tespla/venv/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1802, in _execute_context
    self.dialect.do_execute(
  File "/Users/m0nst3r/dev/py/tespla/venv/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 732, in do_execute
    cursor.execute(statement, parameters)
sqlite3.InterfaceError: Error binding parameter 4 - probably unsupported type.

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

Traceback (most recent call last):
  File "/Users/m0nst3r/dev/py/tespla/venv/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py", line 376, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/Users/m0nst3r/dev/py/tespla/venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "/Users/m0nst3r/dev/py/tespla/venv/lib/python3.9/site-packages/fastapi/applications.py", line 208, in __call__
    await super().__call__(scope, receive, send)
......
 File "/Users/m0nst3r/dev/py/tespla/venv/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/Users/m0nst3r/dev/py/tespla/venv/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1802, in _execute_context
    self.dialect.do_execute(
  File "/Users/m0nst3r/dev/py/tespla/venv/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 732, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.InterfaceError: (sqlite3.InterfaceError) Error binding parameter 4 - probably unsupported type.
[SQL: INSERT INTO task (name, report_id, target, version, md5, onsite, envs, client_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?)]
[parameters: ('task1', '3fa85f6457174562b3fc2c963f66afa6', HttpUrl('http://a.com', scheme='http', host='a.com', tld='com', host_type='domain'), 'v1.0', {'app.zip': '1231231231231234'}, 0, {'apache': '5.0'}, 0)]
(Background on this error at: https://sqlalche.me/e/14/rvf5)

But if I quote the embeded json to the following:

{
  "name": "task1",
  "report_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "target": "http://a.com",
  "version": "v1.0",
  "md5": "{
    \"app.zip\": \"1231231231231234\"
  }",
  "onsite": false,
  "envs": "{
    \"apache\": \"5.0\"
  }",
  "client_id": 0
}

it’s showing: INFO: 127.0.0.1:57231 - "POST /tasks/ HTTP/1.1" 422 Unprocessable Entity

It only works when no embeded json inside, but I need the md5 and envs fields.

Appreciate!

Operating System

macOS

Operating System Details

pip freeze
anyio==3.4.0
arrow==1.2.1
asgiref==3.4.1
binaryornot==0.4.4
certifi==2021.10.8
chardet==4.0.0
charset-normalizer==2.0.10
click==8.0.3
cookiecutter==1.7.3
dnspython==2.2.0
email-validator==1.1.3
fastapi==0.70.1
h11==0.12.0
httptools==0.3.0
idna==3.3
Jinja2==3.0.3
jinja2-time==0.2.0
jose==1.0.0
MarkupSafe==2.0.1
poyo==0.5.0
pydantic==1.8.2
python-dateutil==2.8.2
python-dotenv==0.19.2
python-slugify==5.0.2
PyYAML==6.0
requests==2.27.1
six==1.16.0
sniffio==1.2.0
SQLAlchemy==1.4.29
sqlalchemy2-stubs==0.0.2a19
sqlmodel==0.0.6
starlette==0.16.0
text-unidecode==1.3
typing_extensions==4.0.1
urllib3==1.26.8
uvicorn==0.16.0
uvloop==0.16.0
watchgod==0.7
websockets==10.1

SQLModel Version

0.0.6

Python Version

Python 3.9.9

Additional Context

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 15 (7 by maintainers)

Most upvoted comments

You are better off providing a minimal example that reproduces the error instead of pasting your application code: Client and Vuln are missing now, making it hard for people to reproduce your issue.

The problem seems to be that you are trying to save a dictionary into a database text field. You should find a way to translate between the two or declare a different column type. With PostgreSQL, for example, you could do this and get the translation for free:

from typing import Dict, Optional
from sqlmodel import JSON, Column, Field


class TaskCreate(SQLModel):
    md5: Optional[Dict[str, str]] = Field(sa_column=Column(JSON))