platxa-error-handling
Guide for structured error handling across Platxa stack. Covers error types, retry patterns with exponential backoff, logging, and HTTP response mapping for Python, TypeScript, and Go.
What this skill does
# Platxa Error Handling
Guide for structured error handling patterns across the Platxa platform.
## Overview
| Language | Error Type | Retry Pattern | Logging |
|----------|------------|---------------|---------|
| **Python** | Exceptions (ValueError, PermissionError) | Polling with timeout | logging + audit |
| **TypeScript** | NormalizedError, ConnectionError | Exponential backoff + jitter | Console, events |
| **Go** | WakeError struct, sentinel errors | Retryable map + context timeout | slog JSON |
## Core Principles
1. **Dual Messages**: User-friendly message + technical detail
2. **Error Classification**: Severity, source, retryability
3. **Never Log Secrets**: Only log key names, not values
4. **Fail Fast**: Validate inputs before operations
5. **Preserve Error Chain**: Wrap errors with context
## Structured Error Types
### Python Exceptions
```python
# Semantic exception types
raise ValueError(f"Invalid domain format: {domain}")
raise PermissionError("You don't have permission to provision this instance")
# Kubernetes API exceptions
from kubernetes.client.rest import ApiException
try:
core_v1.read_namespace(namespace)
except ApiException as e:
if e.status == 404: # Expected - create new
core_v1.create_namespace(body)
elif e.status == 409: # Conflict - already exists
_logger.info(f"Resource already exists")
else:
raise # Unexpected - re-raise
```
### TypeScript Error Types
```typescript
// Normalized error format
interface NormalizedError {
id: string;
type: string; // Error class name
message: string; // Human-readable
severity: 'error' | 'warning' | 'info' | 'hint';
source: 'exception' | 'static' | 'runtime' | 'build' | 'test';
code?: string; // Error code (TS2322, E1001)
location?: SourceLocation;
raw: string; // Original error text
timestamp: Date;
}
// Connection error classification
type ConnectionErrorType =
| 'NETWORK_ERROR'
| 'AUTH_ERROR'
| 'TIMEOUT'
| 'SERVER_ERROR'
| 'RATE_LIMITED';
```
### Go Custom Errors
```go
// WakeError with dual messages
type WakeError struct {
Code ErrorCode
UserMessage string // Safe for users
TechnicalDetail string // For logs/support
RetryAllowed bool
SupportRef string
Timestamp time.Time
}
// Error codes as typed constants
type ErrorCode string
const (
CodeImagePullFailed ErrorCode = "IMAGE_PULL_FAILED"
CodeCrashLoop ErrorCode = "CRASH_LOOP"
CodeOOMKilled ErrorCode = "OUT_OF_MEMORY"
CodeStartupTimeout ErrorCode = "STARTUP_TIMEOUT"
)
// Sentinel errors
var ErrBodyTooLarge = fmt.Errorf("request body too large")
```
## Error Classification
### Severity Levels
| Level | Python | TypeScript | Go | Usage |
|-------|--------|------------|-----|-------|
| Error | Exception raised | severity: 'error' | slog.Error | Operation failed |
| Warning | _logger.warning | severity: 'warning' | slog.Warn | Degraded but working |
| Info | _logger.info | severity: 'info' | slog.Info | Normal operation |
### Retryability
```typescript
// TypeScript: Retryable classification
const retryableErrors = ['NETWORK_ERROR', 'TIMEOUT', 'SERVER_ERROR'];
const nonRetryableErrors = ['AUTH_ERROR', 'RATE_LIMITED'];
```
```go
// Go: Retryable map
var retryableErrors = map[ErrorCode]bool{
CodeEvicted: true,
CodeStartupTimeout: true,
CodeScaleUpFailed: true,
CodeImagePullFailed: false, // Non-retryable
CodeCrashLoop: false,
}
func IsRetryable(code ErrorCode) bool {
return retryableErrors[code]
}
```
## Retry Patterns
### Exponential Backoff with Jitter
```typescript
function calculateDelay(attempt: number, baseDelay = 1000, maxDelay = 30000): number {
const delay = baseDelay * Math.pow(2, attempt); // Exponential
const jitter = delay * 0.25 * (Math.random() * 2 - 1); // ±25% jitter
return Math.min(delay + jitter, maxDelay); // Cap at max
}
```
### Python Polling with Timeout
```python
import time
def wake_instance(self, instance):
"""Wake instance with timeout."""
start_time = time.time()
timeout = 30 # seconds
while time.time() - start_time < timeout:
status, _ = self.get_pod_status(instance)
if status == 'running':
return True, int((time.time() - start_time) * 1000)
time.sleep(1)
return False, None # Timeout
```
### Go Context Timeout
```go
func (s *Scaler) waitForReady(ctx context.Context, namespace string) error {
ctx, cancel := context.WithTimeout(ctx, s.config.WakeTimeout)
defer cancel()
for {
select {
case <-ctx.Done():
if ctx.Err() == context.DeadlineExceeded {
return fmt.Errorf("timeout waiting for pod ready")
}
return ctx.Err()
default:
if s.isPodReady(namespace) {
return nil
}
time.Sleep(time.Second)
}
}
}
```
## Error Logging
### Python Structured Logging
```python
import logging
import json
_logger = logging.getLogger(__name__)
_audit_logger = logging.getLogger('instance_manager.audit')
def _audit_log(self, action, resource_type, resource_name, result='success', details=None):
log_entry = {
'timestamp': datetime.now().isoformat(),
'action': action,
'resource_type': resource_type,
'resource_name': resource_name,
'result': result,
'user_id': self.env.user.id,
'details': details, # Never include secrets!
}
_audit_logger.info(json.dumps(log_entry))
# Security: Log key names, not values
security._audit_log(
action='create_secret',
details={'keys': list(secret_data.keys())} # Only key names
)
```
### Go Structured Logging (slog)
```go
import "log/slog"
// Setup with JSON output
func Setup(level string, jsonFormat bool) {
opts := &slog.HandlerOptions{Level: parseLevel(level)}
var handler slog.Handler
if jsonFormat {
handler = slog.NewJSONHandler(os.Stdout, opts)
} else {
handler = slog.NewTextHandler(os.Stdout, opts)
}
slog.SetDefault(slog.New(handler))
}
// Consistent field keys
const (
KeyError = "error"
KeyErrorCode = "error_code"
KeyDurationMS = "duration_ms"
)
// Usage
slog.Error("scale-up failed",
"namespace", namespace,
"error", err,
)
```
## HTTP Error Responses
### Status Code Mapping
| Error Type | HTTP Status | When to Use |
|------------|-------------|-------------|
| Validation error | 400 Bad Request | Invalid input |
| Authentication error | 401 Unauthorized | Missing/invalid token |
| Authorization error | 403 Forbidden | Insufficient permissions |
| Resource not found | 404 Not Found | Missing resource |
| Rate limit | 429 Too Many Requests | Throttled |
| Server error | 500 Internal Server Error | Unexpected error |
| Service unavailable | 503 Service Unavailable | Temporary unavailable |
| Timeout | 504 Gateway Timeout | Upstream timeout |
### Python (FastAPI/Werkzeug)
```python
from werkzeug.exceptions import Unauthorized, BadRequest
# Validation error
if not valid_input(data):
raise BadRequest("Invalid JSON payload")
# Auth error
if not verify_token(request):
raise Unauthorized("Invalid or missing Bearer token")
# JSON response wrapper
def _json_response(self, data, status=200):
return Response(
json.dumps(data),
status=status,
mimetype='application/json'
)
```
### Go HTTP Responses
```go
// Map errors to status codes
func errorHandler(w http.ResponseWriter, r *http.Request, err error) {
if r.Context().Err() != nil {
return // Client disconnected
}
if isConnectionRefused(err) {
http.Error(w, "Instance is not ready", http.StatusBadGateway)
return
}
if isTimeout(err) {
http.Error(w, "Request timed out", http.StatusGatRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.