Trying to use django_scheduled_tasks, but unable to migrate

Hi, I want to run scheduled task on my server, so I try to install django_scheduled_tasks:

INSTALLED_APPS = [
    .
    .
    .
    'django_scheduled_tasks',
    .
    .
    .
]

but when running python3 manage.py migrate, the command fails (just show last few lines in terminal for simple):

.
.
.
File "(my private path)|cursors.py", line 330, in _query
    db.query(q)
    ~~~~~~~~^^^
  File "(my private path)|connections.py", line 286, in query
    _mysql.connection.query(self, query)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.OperationalError: (1170, "BLOB/TEXT column 'task_hash' used in key specification without a key length")

What is the problem (my project is using MySQL)?

When requesting assistance with an issue, please post the complete traceback along with all other output generated by the command.

Additionally, please specific what versions of Python and Django you are using, along with the versions of any third-party apps identified in the project.

Hi, just retried using a new virtual world testworld and testproject with the following commands:

python3 -m venv testworld
cd testworld
source bin/activate
python -m pip install Django
export MYSQLCLIENT_CFLAGS="-I/usr/local/mysql/include"
export MYSQLCLIENT_LDFLAGS="-L/usr/local/mysql/lib -lmysqlclient"
pip install mysqlclient
pip install django_scheduled_tasks
django-admin startproject testproject

then I modify testproject/testproject/settings.py to specify this project use mysql and django_scheduled_tasks :

.
.
.
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_scheduled_tasks'
]
.
.
.
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': (private),
        'USER': (private),              # Your MySQL username
        'PASSWORD': (private),  # Your MySQL password
        'HOST': (private),         # Or your server IP
        'PORT': (private),              # Default MySQL port
    }
}
.
.
.

when running command python3 manage.py makemigrations , it seems look normal, but when running python3 manage.py migrate, the following error occurs:

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, django_scheduled_tasks, sessions
Running migrations:
  Applying django_scheduled_tasks.0001_initial...Traceback (most recent call last):
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/utils.py", line 103, in _execute
    return self.cursor.execute(sql)
           ~~~~~~~~~~~~~~~~~~~^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/mysql/base.py", line 78, in execute
    return self.cursor.execute(query, args)
           ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/MySQLdb/cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/MySQLdb/cursors.py", line 330, in _query
    db.query(q)
    ~~~~~~~~^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/MySQLdb/connections.py", line 286, in query
    _mysql.connection.query(self, query)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
MySQLdb.OperationalError: (1170, "BLOB/TEXT column 'task_hash' used in key specification without a key length")

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

Traceback (most recent call last):
  File "/Users/testuser/Desktop/testworld/testproject/manage.py", line 22, in <module>
    main()
    ~~~~^^
  File "/Users/testuser/Desktop/testworld/testproject/manage.py", line 18, in main
    execute_from_command_line(sys.argv)
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line
    utility.execute()
    ~~~~~~~~~~~~~~~^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/core/management/__init__.py", line 437, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/core/management/base.py", line 420, in run_from_argv
    self.execute(*args, **cmd_options)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/core/management/base.py", line 464, in execute
    output = self.handle(*args, **options)
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/core/management/base.py", line 111, in wrapper
    res = handle_func(*args, **kwargs)
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/core/management/commands/migrate.py", line 354, in handle
    post_migrate_state = executor.migrate(
        targets,
    ...<3 lines>...
        fake_initial=fake_initial,
    )
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/migrations/executor.py", line 137, in migrate
    state = self._migrate_all_forwards(
        state, plan, full_plan, fake=fake, fake_initial=fake_initial
    )
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/migrations/executor.py", line 169, in _migrate_all_forwards
    state = self.apply_migration(
        state, migration, fake=fake, fake_initial=fake_initial
    )
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/migrations/executor.py", line 257, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/migrations/migration.py", line 132, in apply
    operation.database_forwards(
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        self.app_label, schema_editor, old_state, project_state
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/migrations/operations/models.py", line 100, in database_forwards
    schema_editor.create_model(model)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/base/schema.py", line 513, in create_model
    self.execute(sql, params or None)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/base/schema.py", line 205, in execute
    cursor.execute(sql, params)
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/utils.py", line 122, in execute
    return super().execute(sql, params)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/utils.py", line 79, in execute
    return self._execute_with_wrappers(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        sql, params, many=False, executor=self._execute
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/utils.py", line 100, in _execute
    with self.db.wrap_database_errors:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/utils.py", line 94, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/utils.py", line 103, in _execute
    return self.cursor.execute(sql)
           ~~~~~~~~~~~~~~~~~~~^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/django/db/backends/mysql/base.py", line 78, in execute
    return self.cursor.execute(query, args)
           ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/MySQLdb/cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/MySQLdb/cursors.py", line 330, in _query
    db.query(q)
    ~~~~~~~~^^^
  File "/Users/testuser/Desktop/testworld/lib/python3.14/site-packages/MySQLdb/connections.py", line 286, in query
    _mysql.connection.query(self, query)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.OperationalError: (1170, "BLOB/TEXT column 'task_hash' used in key specification without a key length")

Note : when the project just use default sqlite instead of mysql , python3 manage.py migrate is ok.

python version : Python 3.14.5

pip list (including version of django-scheduled-tasks):

annotated-types        0.7.0
asgiref                3.11.1
cron-converter         1.3.1
Django                 6.0.5
django-scheduled-tasks 0.2.18
django-stubs-ext       6.0.4
django-tasks           0.12.0
mysqlclient            2.2.8
pip                    26.1.1
pydantic               2.13.4
pydantic_core          2.46.4
pydantic-extra-types   2.11.1
python-dateutil        2.9.0.post0
six                    1.17.0
sqlparse               0.5.5
typing_extensions      4.15.0
typing-inspection      0.4.2

os : macOS 13.7.8

Note : Originally I want to use django_scheduled_tasks to clear expired sessions regularly, but after retrying installing several times I gave up and decided just using _thread to do my task at AppConfig:

from django.apps import AppConfig
import time
import _thread
from datetime import datetime
class CoreConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'core'
    def ready(self):

        #clean expired tokens every 5 minutes
        from django.contrib.sessions.models import Session
        def cron_job_clean_expired_tokens():
            try:
                for session in list(Session.objects.iterator()):
                    if session.expire_date.timestamp() < datetime.now().timestamp():
                        session.delete()
            except Exception as e:
                print("cron job exception : " + str(e))
            time.sleep(300)
            cron_job_clean_expired_tokens()
        _thread.start_new_thread(cron_job_clean_expired_tokens,())

(error snipped)

If it works for sqlite but not for mysql, then I think your next step would be to file an issue on the django_scheduled_tasks site.

Side note:

This is an extremely bad idea for any project looking to be deployed in a production-quality deployment. (You can find many threads here in the forum explaining why running your own tasks is unwise.)

Also note that Django provides a management command clearsessions precisely for this purpose. For your purposes here, I would recommend using this with whatever other work you might want to do as a cron job. (See Clearing the session store)