Skip to content

RuntimeError: dictionary changed size during iteration when logging in with TOTP

Description:

I'm running Crafty Controller v4.5.4 in a Python virtual environment on a Proxmox LXC container. MFA is enabled and TOTP codes are generated using Google Authenticator. Time synchronization is accurate (NTP-verified), and enable_otp_skew is set to true. When attempting to log in, the UI often becomes unresponsive after submitting the correct username, password, and TOTP code. No error is shown in the frontend, but after a delay (or after retrying with a new TOTP code), the login eventually succeeds. At times, logins require several attempts before the TOTP code is accepted.

However, the following error appears in session.log during the failed attempts:

RuntimeError: dictionary changed size during iteration
  File ".../totp_controller.py", line 104, in clear_stale_entries
    for item, timestamp in totp_dict.items():

This suggests that totp_dict is being modified while being iterated over, which causes the login process to silently fail.

Expected behavior:

TOTP validation should complete without crashing the backend. If a code is invalid or expired, the frontend should receive a proper error response.

Actual behavior:

The backend throws a RuntimeError, and the frontend hangs without feedback.

Environment:

  • Crafty v4.5.4
  • Python 3.11
  • Hosted in LXC container (Debian-based)
  • Accessed via Nginx Proxy Manager (SSL termination via Cloudflare DNS wildcard)
  • Internal Crafty SSL still active on port 8443

Suggested fix:

Wrap the iteration in clear_stale_entries() with a copy of the dictionary keys, e.g.:

for item in list(totp_dict.keys()):
    ...

This would prevent the RuntimeError and allow smoother TOTP validation.

Edited by Dofus Darkwing