Error handling and logging in Python automation scripts
In short: Exceptions are how Python reports problems such as timeouts or bad input. Catch the specific errors you expect, so one failed device does not stop a whole run. Use the logging module, with levels and timestamps, so you can see what happened later, and never log secrets.
Why scripts fail, and why that is fine
Networks are messy. A switch is rebooting, a password has changed, a file is missing, an API returns something unexpected. Python signals each problem by raising an exception. If nothing handles it, the script stops with a traceback showing where it failed. Good automation expects failures, handles the ones it understands, records what happened and carries on safely.
Handling exceptions
Wrap the risky part in try and catch specific exception types in except. Use else for code that should run only if nothing went wrong, and finally for clean-up that must always happen.
import json
try:
with open("inventory.json", encoding="utf-8") as f:
inventory = json.load(f)
except FileNotFoundError:
print("inventory.json is missing")
inventory = []
except json.JSONDecodeError as exc:
print(f"inventory.json is not valid JSON: {exc}")
inventory = []
else:
print(f"Loaded {len(inventory)} devices")
Avoid a bare except: or a broad except Exception: pass. They hide real bugs, including typos, and you end up with a script that "works" but does nothing. You can also raise your own errors when input is wrong: raise ValueError("VLAN must be 1-4094").
Keep going when one device fails
In a loop over many devices, handle errors per device and collect the failures for a summary. This example uses Netmiko’s exception classes; the same pattern works with any library.
import os
from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoAuthenticationException, NetmikoTimeoutException
devices = ["192.168.10.11", "192.168.10.12"]
failed = {}
for host in devices:
try:
with ConnectHandler(device_type="cisco_ios", host=host,
username=os.environ["NET_USER"],
password=os.environ["NET_PASS"]) as conn:
print(conn.send_command("show clock"))
except NetmikoTimeoutException:
failed[host] = "timeout"
except NetmikoAuthenticationException:
failed[host] = "authentication failed"
print("Failed:", failed)
Logging instead of print
The logging module adds timestamps, severity levels and output to files, and lets you turn detail up or down without editing code. Set it up once at the top of the script, then use a named logger.
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
handlers=[logging.FileHandler("audit.log"), logging.StreamHandler()],
)
log = logging.getLogger("vlan_audit")
log.info("Starting audit of %d devices", 12)
log.warning("acc-sw2 has VLAN 1 on an access port")
try:
1 / 0
except ZeroDivisionError:
log.exception("Calculation failed") # logs the traceback at ERROR level
Tip: pass values as arguments (log.info("x=%s", x)) rather than building the string yourself. The message is only formatted if that level is enabled.
Security and good practice
- Never log secrets: passwords, API tokens, session cookies or full device configurations containing keys. Log the host and the error type, not the credentials.
- Do not show raw tracebacks to users of a web tool; they can reveal paths and internals. Log them privately instead.
- Use exit codes: finish with
sys.exit(1)when something failed so schedulers and CI (continuous integration) pipelines notice. - Protect log files: restrict permissions and rotate them with
RotatingFileHandlerso they do not fill the disk. - Forward important logs to central syslog or a SIEM (security information and event management) system when the script runs in production.
Practice
Why is except Exception: pass a bad idea?
With the level set to WARNING, which of debug, info, warning and error messages appear?
A login fails and you want to log it. What should and should not appear?
Key takeaways
- Catch specific exceptions; avoid bare except and silent pass.
- Handle errors per device so one failure does not stop the run.
- Use logging with levels, timestamps and files instead of print.
- Never write secrets into logs or show tracebacks to end users.
- Return a non-zero exit code when a scheduled script fails.
Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.