Free tech learning for everyone, from basics to pro

Python for NetworkingProgramming and Application SecurityIntermediate

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.

try / except / else / finallytryrisky actionexcepthandle known errorselseruns if no errorfinallyalways runs
Figure 1. The four parts of Python exception handling and when each one runs.

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

Logging levelsCRITICALscript cannot continueERRORa task failedWARNINGunexpected, still workingINFOnormal progressDEBUGdetail for troubleshooting
Figure 2. Log levels from most to least severe; the configured level hides everything below it.

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 RotatingFileHandler so 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?
It silently swallows every error, including bugs, so failures go unnoticed and the script appears to succeed.
With the level set to WARNING, which of debug, info, warning and error messages appear?
Only warning and error (and critical). Debug and info are below the threshold and are hidden.
A login fails and you want to log it. What should and should not appear?
Log the host, time and that authentication failed. Never log the password or token that was used.

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.
Tracks your learning on this device only. See your progress on the learning paths.

About the author

Mohamed Fayas

Founder of FM TecHub. CCNA certified, with a BTEC HND in Network Engineering, and BEng (Hons) in Computer Networking and Cloud Security. He writes practical, plain-English guides on networking, security and cloud.

More about the author

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.

Stay up to date by email

New notes, tools and security news from FM TecHub, explained simply. Free.

We only use your email to send these updates. See our privacy policy.