Files

6.5 KiB

Telethon Session Repair — Full Recipes

Real repair scripts used in production. Copy-paste and run.

Fix 7-column → 6-column (drop number)

Two 7-column variants exist. ALWAYS check actual column names first.

Variant A: number column (Telethon v2, 2026+)

Columns: dc_id, server_address, port, auth_key, takeout_id, tmp_auth_key, number

Drop the extra number column:

import sqlite3, shutil
from pathlib import Path

SESSION_DIR = Path("sessions_clean")

for f in SESSION_DIR.glob("*.session"):
    db = sqlite3.connect(str(f))
    cur = db.execute("PRAGMA table_info(sessions)")
    cols = [r[1] for r in cur.fetchall()]
    db.close()

    if len(cols) == 7 and "number" in cols:
        shutil.copy(str(f), str(f) + ".bak7cols")
        db = sqlite3.connect(str(f))
        db.execute("""
            CREATE TABLE sessions_new (
                dc_id INT PRIMARY KEY, server_address TEXT, port INT,
                auth_key BLOB, takeout_id INTEGER, tmp_auth_key BLOB
            )
        """)
        db.execute("INSERT INTO sessions_new SELECT dc_id, server_address, port, auth_key, takeout_id, tmp_auth_key FROM sessions")
        db.execute("DROP TABLE sessions")
        db.execute("ALTER TABLE sessions_new RENAME TO sessions")
        db.commit()
        db.close()
        print(f"Fixed: {f.name}")

Variant B: auth_key_id column (older)

Columns: dc_id, server_address, port, auth_key, auth_key_id, takeout_id, tmp_auth_key

Drop the extra auth_key_id column:

import sqlite3, shutil
from pathlib import Path

for f in Path("sessions_clean").glob("*.session"):
    db = sqlite3.connect(str(f))
    cur = db.execute("PRAGMA table_info(sessions)")
    cols = [r[1] for r in cur.fetchall()]
    db.close()

    if len(cols) == 7 and "auth_key_id" in cols:
        shutil.copy(str(f), str(f) + ".bak7cols")
        db = sqlite3.connect(str(f))
        db.execute("""
            CREATE TABLE sessions_new (
                dc_id INT, server_address TEXT, port INT,
                auth_key BLOB, takeout_id INTEGER, tmp_auth_key BLOB
            )
        """)
        db.execute("INSERT INTO sessions_new SELECT dc_id, server_address, port, auth_key, takeout_id, tmp_auth_key FROM sessions")
        db.execute("DROP TABLE sessions")
        db.execute("ALTER TABLE sessions_new RENAME TO sessions")
        db.commit()
        db.close()
        print(f"Fixed: {f.name}")

Fix 5-column → 6-column

Two 5-column variants exist. ALWAYS check the actual column names before repairing.

Variant A: missing takeout_id (cols: dc_id, server_address, port, auth_key, auth_key_id)

Older Telethon v7 sessions. Add takeout_id as NULL.

import sqlite3, shutil
from pathlib import Path

for f in Path("sessions_clean").glob("*.session"):
    db = sqlite3.connect(str(f))
    cur = db.execute("PRAGMA table_info(sessions)")
    cols = [r[1] for r in cur.fetchall()]
    db.close()

    if len(cols) == 5 and "auth_key_id" in cols:
        shutil.copy(str(f), str(f) + ".bak5cols")
        db = sqlite3.connect(str(f))
        db.execute("""
            CREATE TABLE sessions_new (
                dc_id INT, server_address TEXT, port INT,
                auth_key BLOB, auth_key_id BLOB, takeout_id INTEGER
            )
        """)
        db.execute("INSERT INTO sessions_new SELECT dc_id, server_address, port, auth_key, auth_key_id, NULL FROM sessions")
        db.execute("DROP TABLE sessions")
        db.execute("ALTER TABLE sessions_new RENAME TO sessions")
        db.commit()
        db.close()
        print(f"Fixed: {f.name}")

Variant B: missing auth_key_id (cols: dc_id, server_address, port, auth_key, takeout_id)

Encountered on MAINTG1.session (2026-07-28). This schema has takeout_id but no auth_key_id. Add auth_key_id as NULL.

# PROVEN on MAINTG1.session (C:\Users\User\Desktop\_PROJECTS\tg_content_agent\)
import sqlite3, shutil

f = "MAINTG1.session"
db = sqlite3.connect(f)
cols = [r[1] for r in db.execute("PRAGMA table_info(sessions)")]
print(f"Cols: {cols}")
# Expected: ['dc_id', 'server_address', 'port', 'auth_key', 'takeout_id']

if len(cols) == 5 and "takeout_id" in cols and "auth_key_id" not in cols:
    shutil.copy(f, f + ".bak5cols_v2")
    db.execute("""
        CREATE TABLE sessions_new (
            dc_id INT, server_address TEXT, port INT,
            auth_key BLOB, auth_key_id BLOB, takeout_id INTEGER
        )
    """)
    db.execute("INSERT INTO sessions_new SELECT dc_id, server_address, port, auth_key, NULL, takeout_id FROM sessions")
    db.execute("DROP TABLE sessions")
    db.execute("ALTER TABLE sessions_new RENAME TO sessions")
    db.commit()
    # Verify
    new_cols = [r[1] for r in db.execute("PRAGMA table_info(sessions)")]
    row = db.execute("SELECT * FROM sessions").fetchone()
    assert len(new_cols) == 6, f"Expected 6 cols, got {len(new_cols)}"
    print(f"Fixed: {new_cols}, auth_key_len={len(row[3]) if row[3] else 0}")
db.close()

Bulk session health check

import sqlite3
from pathlib import Path

for d in ["sessions5", "sessions_clean", "session", "sessions_archive"]:
    sd = Path(d)
    if not sd.exists():
        continue
    for f in sorted(sd.glob("*.session")):
        try:
            db = sqlite3.connect(str(f))
            cur = db.execute("PRAGMA table_info(sessions)")
            cols = [r[1] for r in cur.fetchall()]
            cur = db.execute("SELECT * FROM sessions")
            row = cur.fetchone()
            db.close()
            status = "OK" if len(cols) == 6 and row and len(row) == 6 else f"BAD cols={len(cols)} row={len(row) if row else 0}"
            print(f"{d}/{f.stem}: {status}")
        except Exception as e:
            print(f"{d}/{f.stem}: ERROR {e}")

Check for corrupted auth_key (causes TypeError: Strings must be encoded before hashing)

import sqlite3
from pathlib import Path

for d in ["sessions5", "sessions_clean"]:
    for f in Path(d).glob("*.session"):
        db = sqlite3.connect(str(f))
        cur = db.execute("SELECT auth_key FROM sessions")
        row = cur.fetchone()
        db.close()
        if row and row[0] is not None:
            ak = row[0]
            if isinstance(ak, str):
                print(f"BAD (string auth_key): {f}")
            elif isinstance(ak, bytes):
                if len(ak) < 100:
                    print(f"SUSPECT (short auth_key {len(ak)}b): {f}")
            else:
                print(f"BAD (type {type(ak).__name__}): {f}")
        else:
            print(f"NULL auth_key: {f}")