Your capstone sends emails, reads sheets, creates events. What happens if Gmail's connection expires mid-workflow?
The execute_action call raises an exception. Without error handling, the whole workflow crashes and I don't know which step failed.
Exactly. In production workflows, each API call can fail independently. The pattern is to wrap the risky call in try/except and return a structured error dict so the caller knows what happened:
def safe_send(to: str, subject: str, body: str) -> dict:
try:
result = toolset.execute_action(
Action.GMAIL_SEND_EMAIL,
{"recipient_email": to, "subject": subject, "body": body}
)
return result
except Exception as e:
if "AUTH_REQUIRED" in str(e):
print("Gmail not connected — reconnect in settings")
return {"error": "AUTH_REQUIRED", "message": str(e)}
raiseWhy raise at the end instead of catching everything?
Only catch errors you can handle. AUTH_REQUIRED has a clear fix — reconnect in settings. An unknown exception (network error, API change) should propagate so you see the real error. Catching everything silences bugs:
def safe_send(to: str, subject: str, body: str) -> dict:
try:
result = toolset.execute_action(
Action.GMAIL_SEND_EMAIL,
{"recipient_email": to, "subject": subject, "body": body}
)
print(f"Email sent to {to}: {subject}")
return result
except Exception as e:
error_str = str(e)
if "AUTH_REQUIRED" in error_str:
print(f"Gmail auth expired — reconnect in settings")
return {"error": "AUTH_REQUIRED", "message": error_str}
raiseThe capstone calls safe_send instead of send_email — same interface, but the calling function can check result.get('error') to decide whether to continue the workflow.
That's the pattern. Error-aware wrappers keep workflow logic clean. The capstone checks the return value and stops early if 'error' in result. You've separated the network concern from the workflow logic.
Could I apply the same pattern to read_doc or find_events if those connections expire too?
Yes. The pattern is universal: wrap any execute_action call in try/except, check for AUTH_REQUIRED in the error string, return a structured dict, and re-raise everything else. Each action type may surface different auth error strings — test each one separately.
try:
result = toolset.execute_action(...)
return result
except Exception as e:
if "AUTH_REQUIRED" in str(e):
return {"error": "AUTH_REQUIRED", "message": str(e)}
raiseOnly catch errors you understand and can describe to the caller. AUTH_REQUIRED has a clear fix — reconnect in settings. Unknown exceptions should propagate with their full stack trace so you can debug them.
if 'error' in result: return result — propagate the error dict upward. The top-level caller decides whether to retry, alert, or abort the workflow.
Never use bare except Exception: pass. Silent failures are worse than crashes.
Your capstone sends emails, reads sheets, creates events. What happens if Gmail's connection expires mid-workflow?
The execute_action call raises an exception. Without error handling, the whole workflow crashes and I don't know which step failed.
Exactly. In production workflows, each API call can fail independently. The pattern is to wrap the risky call in try/except and return a structured error dict so the caller knows what happened:
def safe_send(to: str, subject: str, body: str) -> dict:
try:
result = toolset.execute_action(
Action.GMAIL_SEND_EMAIL,
{"recipient_email": to, "subject": subject, "body": body}
)
return result
except Exception as e:
if "AUTH_REQUIRED" in str(e):
print("Gmail not connected — reconnect in settings")
return {"error": "AUTH_REQUIRED", "message": str(e)}
raiseWhy raise at the end instead of catching everything?
Only catch errors you can handle. AUTH_REQUIRED has a clear fix — reconnect in settings. An unknown exception (network error, API change) should propagate so you see the real error. Catching everything silences bugs:
def safe_send(to: str, subject: str, body: str) -> dict:
try:
result = toolset.execute_action(
Action.GMAIL_SEND_EMAIL,
{"recipient_email": to, "subject": subject, "body": body}
)
print(f"Email sent to {to}: {subject}")
return result
except Exception as e:
error_str = str(e)
if "AUTH_REQUIRED" in error_str:
print(f"Gmail auth expired — reconnect in settings")
return {"error": "AUTH_REQUIRED", "message": error_str}
raiseThe capstone calls safe_send instead of send_email — same interface, but the calling function can check result.get('error') to decide whether to continue the workflow.
That's the pattern. Error-aware wrappers keep workflow logic clean. The capstone checks the return value and stops early if 'error' in result. You've separated the network concern from the workflow logic.
Could I apply the same pattern to read_doc or find_events if those connections expire too?
Yes. The pattern is universal: wrap any execute_action call in try/except, check for AUTH_REQUIRED in the error string, return a structured dict, and re-raise everything else. Each action type may surface different auth error strings — test each one separately.
try:
result = toolset.execute_action(...)
return result
except Exception as e:
if "AUTH_REQUIRED" in str(e):
return {"error": "AUTH_REQUIRED", "message": str(e)}
raiseOnly catch errors you understand and can describe to the caller. AUTH_REQUIRED has a clear fix — reconnect in settings. Unknown exceptions should propagate with their full stack trace so you can debug them.
if 'error' in result: return result — propagate the error dict upward. The top-level caller decides whether to retry, alert, or abort the workflow.
Never use bare except Exception: pass. Silent failures are worse than crashes.
Create a free account to get started. Paid plans unlock all tracks.