Replit supports Python debugging through pdb (Python Debugger), the logging module, traceback analysis, and memory profiling with tracemalloc. Set breakpoints with pdb.set_trace() or breakpoint(), read stack traces to identify the exact line and function causing errors, replace print statements with structured logging, and use tracemalloc to find memory leaks. All of these tools work directly in Replit's Shell and Console without any extensions.
How to Debug Advanced Python Issues in Replit
Debugging Python goes beyond adding print statements. This tutorial covers four professional debugging techniques that work inside Replit: the built-in pdb debugger for stepping through code line by line, structured logging for tracking application behavior, traceback analysis for reading error messages effectively, and tracemalloc for identifying memory issues. These skills are essential as your Python projects grow more complex.
Prerequisites
- A Replit account with a Python project (any plan)
- Basic Python knowledge including functions, variables, and imports
- Access to the Shell tab in the Replit workspace
- Familiarity with running Python scripts from the command line
Step-by-step guide
Use pdb to set breakpoints and step through code
Use pdb to set breakpoints and step through code
Python's built-in debugger pdb lets you pause execution at any line, inspect variables, and step through code one line at a time. Add breakpoint() (Python 3.7+) or import pdb; pdb.set_trace() at the line where you want to pause. Run your script from the Shell (not the Run button) so you can interact with the debugger. When execution pauses, use commands like n (next line), s (step into function), p variable (print value), c (continue), and q (quit). This is far more effective than scattering print statements.
1# example.py2def calculate_total(items):3 total = 04 for item in items:5 breakpoint() # Execution pauses here6 total += item['price'] * item['quantity']7 return total89items = [10 {'name': 'Widget', 'price': 9.99, 'quantity': 3},11 {'name': 'Gadget', 'price': 24.99, 'quantity': 1},12 {'name': 'Doohickey', 'price': None, 'quantity': 2}, # Bug: None price13]1415result = calculate_total(items)16print(f'Total: ${result:.2f}')Expected result: Execution pauses at the breakpoint. You can type p item to see the current item, p total to see the running total, and n to proceed to the next line.
Read Python traceback messages to locate errors
Read Python traceback messages to locate errors
When Python crashes, it prints a traceback showing the chain of function calls that led to the error. Read tracebacks from bottom to top: the last line is the actual error type and message, and the lines above show each function call with file name and line number. The most recent call is at the bottom. Common error types are TypeError (wrong data type), KeyError (missing dictionary key), AttributeError (calling a method on the wrong type), and IndexError (list index out of range). Understanding tracebacks lets you go straight to the bug instead of guessing.
1# This code produces a traceback:2def get_user_email(users, user_id):3 user = users[user_id] # Line that crashes4 return user['email']56users = {'alice': {'email': 'alice@example.com'}}7email = get_user_email(users, 'bob') # 'bob' not in dict89# Traceback output:10# Traceback (most recent call last):11# File "main.py", line 6, in <module>12# email = get_user_email(users, 'bob')13# File "main.py", line 2, in get_user_email14# user = users[user_id]15# KeyError: 'bob'1617# Fix: use .get() with a default18def get_user_email(users, user_id):19 user = users.get(user_id)20 if user is None:21 return None22 return user['email']Expected result: You can read the traceback, identify that the error is a KeyError on line 2 caused by 'bob' not existing in the dictionary, and apply the fix.
Replace print statements with the logging module
Replace print statements with the logging module
The logging module provides structured, leveled output that you can filter by severity. Instead of print('something happened'), use logging.info('something happened'). Logging supports levels: DEBUG (detailed), INFO (general), WARNING (potential issues), ERROR (failures), and CRITICAL (fatal). You can configure it to include timestamps, file names, and line numbers automatically. Unlike print statements, logging can be turned off for production by changing the log level without removing any code.
1import logging23# Configure logging with timestamps and levels4logging.basicConfig(5 level=logging.DEBUG,6 format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',7 datefmt='%H:%M:%S'8)910logger = logging.getLogger('myapp')1112def process_order(order):13 logger.info(f"Processing order {order['id']}")14 logger.debug(f"Order details: {order}")1516 if order['total'] <= 0:17 logger.warning(f"Order {order['id']} has zero or negative total")18 return False1920 try:21 # Simulate payment processing22 charge_payment(order)23 logger.info(f"Order {order['id']} completed successfully")24 return True25 except Exception as e:26 logger.error(f"Payment failed for order {order['id']}: {e}")27 return FalseExpected result: Your output shows timestamped, leveled messages like '14:32:01 [INFO] myapp: Processing order 123' that are easy to filter and search.
Profile memory usage with tracemalloc
Profile memory usage with tracemalloc
If your Replit app crashes with 'Your Repl ran out of memory', you need to find what is consuming RAM. Python's built-in tracemalloc module tracks memory allocations and shows you exactly which lines of code allocate the most memory. Start tracing at the beginning of your script, run the memory-intensive operation, then take a snapshot and display the top allocations. This is especially important on Replit's Starter plan with only 2 GiB RAM.
1import tracemalloc23# Start tracing memory allocations4tracemalloc.start()56def load_large_dataset():7 # Simulating a memory-heavy operation8 data = []9 for i in range(100000):10 data.append({'id': i, 'value': f'item_{i}' * 100})11 return data1213# Run the operation14result = load_large_dataset()1516# Take a snapshot and show top memory consumers17snapshot = tracemalloc.take_snapshot()18stats = snapshot.statistics('lineno')1920print('\nTop 10 memory allocations:')21for stat in stats[:10]:22 print(f' {stat}')2324# Show current and peak memory usage25current, peak = tracemalloc.get_traced_memory()26print(f'\nCurrent memory: {current / 1024 / 1024:.1f} MB')27print(f'Peak memory: {peak / 1024 / 1024:.1f} MB')2829tracemalloc.stop()Expected result: You see a ranked list of memory allocations by file and line number, plus total current and peak memory usage in megabytes.
Debug API and network errors with exception chaining
Debug API and network errors with exception chaining
When your Python app calls external APIs, errors can be vague. Use try-except blocks with detailed logging to capture the actual error message, status code, and response body. Python 3 supports exception chaining with raise ... from to preserve the original error context. For HTTP requests using the requests library, always check the status code and log the response text on failure before raising an error.
1import requests2import logging34logger = logging.getLogger('api')56def fetch_weather(city):7 api_key = os.getenv('WEATHER_API_KEY')8 if not api_key:9 raise ValueError('WEATHER_API_KEY not set. Add it in Tools → Secrets.')1011 url = f'https://api.example.com/weather?q={city}&key={api_key}'12 logger.info(f'Fetching weather for {city}')1314 try:15 response = requests.get(url, timeout=10)16 logger.debug(f'Response status: {response.status_code}')1718 if response.status_code != 200:19 logger.error(f'API error {response.status_code}: {response.text}')20 response.raise_for_status()2122 return response.json()23 except requests.Timeout:24 logger.error(f'Request to weather API timed out after 10 seconds')25 raise26 except requests.ConnectionError as e:27 logger.error(f'Cannot connect to weather API: {e}')28 raiseExpected result: When an API call fails, your logs show the exact status code, response body, and error type instead of a generic exception.
Complete working example
1"""debug_utils.py — Python debugging utilities for Replit projects.23Import these helpers during development.4Set DEBUG_MODE=true in Tools → Secrets to enable verbose output.5"""6import os7import logging8import tracemalloc9from functools import wraps10import time1112# Configure logging based on Secrets13log_level = logging.DEBUG if os.getenv('DEBUG_MODE') == 'true' else logging.INFO14logging.basicConfig(15 level=log_level,16 format='%(asctime)s [%(levelname)s] %(name)s (%(filename)s:%(lineno)d): %(message)s',17 datefmt='%H:%M:%S'18)19logger = logging.getLogger('app')202122def timed(func):23 """Decorator that logs how long a function takes to execute."""24 @wraps(func)25 def wrapper(*args, **kwargs):26 start = time.time()27 try:28 result = func(*args, **kwargs)29 elapsed = time.time() - start30 logger.debug(f'{func.__name__} completed in {elapsed:.3f}s')31 return result32 except Exception as e:33 elapsed = time.time() - start34 logger.error(f'{func.__name__} failed after {elapsed:.3f}s: {e}')35 raise36 return wrapper373839def log_memory(label=''):40 """Print current and peak memory usage."""41 if not tracemalloc.is_tracing():42 tracemalloc.start()43 current, peak = tracemalloc.get_traced_memory()44 logger.info(45 f'Memory [{label}]: current={current/1024/1024:.1f}MB, '46 f'peak={peak/1024/1024:.1f}MB'47 )484950def top_memory_allocations(limit=10):51 """Show the top memory-consuming lines of code."""52 if not tracemalloc.is_tracing():53 logger.warning('tracemalloc not started. Call tracemalloc.start() first.')54 return55 snapshot = tracemalloc.take_snapshot()56 stats = snapshot.statistics('lineno')57 logger.info(f'Top {limit} memory allocations:')58 for stat in stats[:limit]:59 logger.info(f' {stat}')606162def safe_request(url, method='GET', timeout=10, **kwargs):63 """Make an HTTP request with full error logging."""64 import requests65 logger.info(f'{method} {url}')66 try:67 response = requests.request(method, url, timeout=timeout, **kwargs)68 logger.debug(f'Response: {response.status_code}')69 if not response.ok:70 logger.error(f'{response.status_code}: {response.text[:500]}')71 return response72 except requests.Timeout:73 logger.error(f'Timeout after {timeout}s: {url}')74 raise75 except requests.ConnectionError as e:76 logger.error(f'Connection failed: {e}')77 raiseCommon mistakes when debugging advanced Python issues in Replit
Why it's a problem: Using the Run button to debug with pdb, which does not support interactive input in Console
How to avoid: Run your script from the Shell tab with python filename.py so you can type pdb commands
Why it's a problem: Leaving breakpoint() calls in code that gets deployed to production
How to avoid: Search your codebase for breakpoint() and pdb.set_trace() before deploying, and remove or conditionally disable them
Why it's a problem: Catching all exceptions with a bare except: clause that hides the actual error
How to avoid: Catch specific exception types like except ValueError as e and always log the error message
Why it's a problem: Using print(object) for debugging dictionaries and getting unhelpful output
How to avoid: Use import json; print(json.dumps(obj, indent=2, default=str)) for readable, formatted output
Why it's a problem: Not setting timeouts on requests.get() calls, causing the Repl to hang indefinitely
How to avoid: Always pass timeout=10 (or an appropriate value) to requests.get() and requests.post()
Best practices
- Run pdb from the Shell tab, not the Run button, because Console does not support interactive debugger input
- Read Python tracebacks from bottom to top: the last line is the error, the lines above show the call chain
- Use the logging module with severity levels instead of print statements for structured, filterable output
- Set a DEBUG_MODE secret in Tools → Secrets to toggle verbose logging without changing code
- Always set timeouts on HTTP requests to prevent frozen Repls from consuming resources
- Use tracemalloc proactively before your app hits the memory limit, especially on the 2 GiB Starter plan
- Add type hints to function signatures so tracebacks are easier to understand when type errors occur
- Delete breakpoint() calls before deploying — they will freeze your production app
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
My Python script on Replit crashes with 'TypeError: unsupported operand type(s)' but the traceback points to a line inside a loop. How do I use pdb to find which iteration of the loop contains the bad data? Show me the pdb commands to inspect the current variable values.
My Python app is using too much memory and crashing with 'Your Repl ran out of memory'. Add tracemalloc to my main.py to track memory allocations. Show me the top 10 memory-consuming lines and current vs peak memory usage. Also add a @timed decorator to the three largest functions.
Frequently asked questions
Replit does not have a built-in visual debugger with a GUI. However, Python's built-in pdb works in the Shell tab, providing interactive breakpoints, variable inspection, and step-through execution. For complex debugging needs, teams can consult RapidDev for guidance on advanced debugging strategies.
The Run button sends output to the Console tab, which is read-only and does not support interactive input. Run your script from the Shell tab instead with python filename.py so you can type pdb commands.
Use the tracemalloc module. Call tracemalloc.start() at the beginning of your script, take snapshots before and after operations, and compare them with snapshot2.compare_to(snapshot1, 'lineno') to see which lines increased memory usage.
Yes, you can configure a FileHandler in logging. However, remember that the file system resets on deployment. For persistent logs in production, use an external logging service or write to the database.
The Starter plan provides 2 GiB RAM. Core provides 8 GiB. Pro provides 8 GiB or more. If your Python app exceeds the limit, Replit kills the process with 'Your Repl ran out of memory'.
A ModuleNotFoundError means the package is not installed. Run pip install package_name in Shell. If it was installed but still fails, check for virtual environment conflicts by running which python and pip list in Shell.
Yes. Install them with pip install ipdb or pip install pdbpp in Shell. Use import ipdb; ipdb.set_trace() for a more feature-rich debugging experience with syntax highlighting and tab completion.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation