HKUDS/DeepTutor · warning · HTTPException
Too many sessions in one request (max {_MAX_SESSIONS_PER_REQ
Error message
Too many sessions in one request (max {_MAX_SESSIONS_PER_REQUEST}) What it means
413 raised by POST /imports/chat-history when payload.sessions exceeds _MAX_SESSIONS_PER_REQUEST, a bulk-import guard preventing oversized single requests.
Source
Thrown at deeptutor/api/routers/imports.py:79
agent_id: str = Field(default="", max_length=256)
agent_name: str = Field(default="", max_length=256)
sessions: list[ImportedSession] = Field(default_factory=list)
@field_validator("source")
@classmethod
def _normalize_source(cls, value: str) -> str:
normalized = (value or "").strip().lower()
if normalized not in _ALLOWED_SOURCES:
raise ValueError(f"Unsupported import source: {value!r}")
return normalized
@router.post("/chat-history")
async def import_chat_history(payload: ChatHistoryImportRequest) -> dict[str, Any]:
if not payload.sessions:
raise HTTPException(status_code=400, detail="No sessions to import")
if len(payload.sessions) > _MAX_SESSIONS_PER_REQUEST:
raise HTTPException(
status_code=413,
detail=f"Too many sessions in one request (max {_MAX_SESSIONS_PER_REQUEST})",
)
store = get_sqlite_session_store()
imported = 0
skipped = 0
results: list[dict[str, Any]] = []
for incoming in payload.sessions:
# Drop content-less rows (e.g. tool-only turns the adapter could not
# reduce to text) so the transcript stays a clean human conversation.
messages = [m for m in incoming.messages if (m.content or "").strip()]
if not messages:
skipped += 1
results.append(
{"external_id": incoming.external_id, "imported": False, "reason": "empty"}
)View on GitHub (pinned to 3e82f13042)
Solutions
- Read the detail to get the max, then split sessions into batches of at most that size
- Add client-side chunking before import
- Verify the server constant (or raise it via config if appropriate) in deeptutor/api/routers/imports.py
Example fix
# before
resp = post('/imports/chat-history', json={'source':'claude','sessions':all_sessions})
# after
MAX = 200
for i in range(0, len(all_sessions), MAX):
post('/imports/chat-history', json={'source':'claude','sessions':all_sessions[i:i+MAX]}) Defensive patterns
Strategy: validation
Validate before calling
MAX = 200 # keep in sync with _MAX_SESSIONS_PER_REQUEST
for i in range(0, len(sessions), MAX):
import_batch(sessions[i:i + MAX]) Try / catch
resp = client.post('/imports/chat-history', json=payload)
if resp.status_code == 413:
max_n = int(re.search(r'max (\d+)', resp.text).group(1))
for i in range(0, len(sessions), max_n):
client.post('/imports/chat-history', json={**payload, 'sessions': sessions[i:i + max_n]}) Prevention
- Always batch large imports
- Read the limit from the 413 detail and adapt dynamically
When it happens
Trigger: POSTing an import with more sessions than the constant allows (e.g. thousands of sessions in one body).
Common situations: Migrating a large multi-year chat history in a single call; no client-side batching.
Related errors
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/aec80ca3da3e4811.
Report an issue: GitHub.