Error Handling

All API errors return a consistent JSON envelope:

{
  "error": {
    "code": "ERROR_TYPE",
    "message": "Human-readable description",
    "details": ["..."]
  }
}

HTTP Status Codes

Code

Meaning

400

Invalid JSON or malformed GeoJSON

404

File or endpoint not found

422

Valid JSON but building attributes fail validation

500

Model execution error or unexpected failure

Error Categories

VALIDATION_ERROR

Missing or out-of-range building attributes (e.g. negative U-value, missing components).

GEOJSON_ERROR

Structural problems with the GeoJSON payload (e.g. missing type, features not an array).

MODEL_ERROR

Thermal solver failure (e.g. LP infeasible, weather file missing).

FILE_ERROR

Requested timeseries file not found on disk.

Debugging Checklist

  1. Validate JSON syntax and GeoJSON structure before sending.

  2. Ensure all component U-values are positive and areas > 0.

  3. Check that total window area does not exceed its parent wall area.

  4. Verify BUEM_WEATHER_DIR is set and the CSV file exists.

  5. Review container logs: docker logs buem-api.

  6. Verify file permissions for results directory.

Error Recovery Strategies

Retry Logic

For transient server errors (5xx), implement exponential backoff:

import time
import requests

def api_call_with_retry(url, data, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=data)
            if response.status_code < 500:
                return response
            time.sleep(2 ** attempt)
        except requests.RequestException:
            time.sleep(2 ** attempt)
    return None

Batch Processing Recovery

For large batches, process features individually on errors:

def process_building_batch(buildings):
    successful = []
    failed = []

    # Try batch first
    try:
        response = api_call({"type": "FeatureCollection", "features": buildings})
        return response
    except Exception:
        # Fall back to individual processing
        for building in buildings:
            try:
                result = api_call({"type": "Feature", **building})
                successful.append(result)
            except Exception as e:
                failed.append({"building": building["id"], "error": str(e)})

    return {"successful": successful, "failed": failed}

Validation Pre-check

Validate requests locally before sending to API:

def validate_building_request(feature):
    errors = []

    # Check required structure
    if "properties" not in feature:
        errors.append("Missing properties")

    attrs = feature.get("properties", {}).get("buem", {}).get("building_attributes", {})

    # Check required attributes
    required = ["latitude", "longitude", "A_ref", "components"]
    for field in required:
        if field not in attrs:
            errors.append(f"Missing required field: {field}")

    # Check numeric ranges
    if "latitude" in attrs:
        lat = attrs["latitude"]
        if not -90 <= lat <= 90:
            errors.append(f"Invalid latitude: {lat}")

    return errors

Production Considerations

Logging and Monitoring

  • Log all API responses with status codes

  • Monitor error rates and patterns

  • Set up alerts for high error rates or specific error types

  • Track processing times for performance monitoring

Error Notification

def handle_api_error(response):
    if response.status_code >= 400:
        error_data = response.json().get("error", {})

        # Log structured error data
        logger.error("BuEM API Error", extra={
            "error_code": error_data.get("code"),
            "message": error_data.get("message"),
            "details": error_data.get("details"),
            "status_code": response.status_code
        })

        # Send alerts for critical errors
        if response.status_code >= 500:
            send_alert(f"BuEM API server error: {error_data.get('message')}")

Next Steps

Continue to Integration Examples for complete integration examples showing error handling in practice.