nexu-io/open-design · error · SystemExit
json.dumps(response["error"], indent=2)
Error message
json.dumps(response["error"], indent=2)
What it means
Raised by run_image_edit (and identically by run_image_generation) after the OpenAI image API returned a JSON body containing a non-empty 'error' field. The full error object is pretty-printed so the caller sees the API's own message, code, and details rather than a generic failure.
Source
Thrown at skills/hatch-pet/scripts/generate_pet_images.py:119
for image_path in image_paths:
fields.append(("image[]", (image_path.name, image_path.read_bytes(), "image/png")))
fields.extend([
("prompt", prompt_file.read_text(encoding="utf-8")),
("size", size),
("output_format", "png"),
])
body, content_type = _multipart_body(fields)
req = urllib.request.Request(
"https://api.openai.com/v1/images/edits",
data=body,
headers={"Authorization": f"Bearer {api_key}", "Content-Type": content_type},
method="POST",
)
with urllib.request.urlopen(req, timeout=300) as resp:
output_json.write_bytes(resp.read())
response = json.loads(output_json.read_text(encoding="utf-8"))
if response.get("error"):
raise SystemExit(json.dumps(response["error"], indent=2))
return response
def run_image_generation(
*,
model: str,
prompt_file: Path,
output_json: Path,
size: str,
api_key: str,
) -> dict[str, object]:
output_json.parent.mkdir(parents=True, exist_ok=True)
payload = json.dumps({
"model": model,
"prompt": prompt_file.read_text(encoding="utf-8"),
"size": size,
"output_format": "png",
}).encode()View on GitHub (pinned to 5be4028344)
Solutions
- Read the pretty-printed error JSON: the 'code'/'message' fields identify auth, rate-limit, moderation, or validation failures.
- For 401/auth errors: rotate or refresh OPENAI_API_KEY and confirm it has image permissions.
- For 429 rate limits: wait and retry with fewer concurrent jobs, or reduce the --states set.
- For moderation/validation errors: adjust the prompt_file or input image and re-run that specific job with --job-id.
Defensive patterns
Strategy: retry
Validate before calling
response = json.loads(output_json.read_text())
err = response.get('error')
if err:
code = err.get('code') if isinstance(err, dict) else None
if code in ('rate_limit_exceeded','server_error','timeout'):
raiseTransient(err) # retry after backoff
raisePermanent(err) # auth/moderation/validation - do not retry Type guard
def is_transient_api_error(err: object) -> bool:
if not isinstance(err, dict):
return False
code = str(err.get('code') or '').lower()
msg = str(err.get('message') or '').lower()
return 'rate' in code or 'rate' in msg or code in ('server_error','timeout','service_unavailable') Try / catch
import json, time, urllib.error
for attempt in range(max_retries):
try:
resp = run_image_edit(...)
if resp.get('error'):
err = resp['error']
if is_transient_api_error(err) and attempt + 1 < max_retries:
time.sleep(2 ** attempt)
continue
raise SystemExit(json.dumps(err, indent=2))
break
except urllib.error.URLError as e:
if attempt + 1 < max_retries:
time.sleep(2 ** attempt); continue
raise Prevention
- Confirm OPENAI_API_KEY has image-edit/generation permissions before batching.
- Throttle concurrent jobs to stay under rate limits.
- Inspect the pretty-printed error JSON to distinguish auth, rate-limit, and moderation failures before retrying.
When it happens
Trigger: urllib succeeds (HTTP 200 or the body still parsed) but response.get('error') is truthy. Typical causes: invalid API key, rate limit, content policy rejection, unsupported size/model, or malformed multipart body.
Common situations: OPENAI_API_KEY expired or lacking image-edit scope; hitting rate limits during a multi-job batch; a prompt or input image flagged by content moderation; passing a size the chosen model does not support.
Related errors
- public_github_repository_metric request failed with ${respon
- Reddit rate limited (429) fetching {url}
- WORKSPACE_AUTHORITY_UNAVAILABLE
- Could not fetch ${url} — the site may block server-side requ
- invalid brand asset url: ${String(url)}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/c68f84b6c6ec2b5a.
Report an issue: GitHub.