Skip to main content

Error Handling

Understand the error responses from the Sistema de Gestión de Propiedades API and how to handle them gracefully in your application.

Error Response Format

The API returns errors in JSON format with appropriate HTTP status codes:
{
  "success": false,
  "error": "Error message here"
}
Or for authentication errors:
{
  "error": "Unauthorized"
}

HTTP Status Codes

The API uses standard HTTP status codes:
Status CodeMeaningDescription
200 OKSuccessRequest completed successfully
201 CreatedCreatedResource created successfully
400 Bad RequestClient ErrorInvalid request data or validation failure
401 UnauthorizedAuth ErrorMissing or invalid authentication
404 Not FoundNot FoundResource doesn’t exist
409 ConflictConflictResource already exists (duplicate ID)

Common Errors

400 Bad Request

Returned when the request data is invalid or fails validation.

Validation Errors

Error:
{
  "success": false,
  "error": "Invalid input: estado must be one of Disponible, Reservado, Alquilado, Vendido"
}
Cause: Provided an invalid value for estado or tipo_contratacionSolution:
// Valid estado values
const validEstados = ['Disponible', 'Reservado', 'Alquilado', 'Vendido'];

// Valid tipo_contratacion values
const validTipos = ['Alquiler', 'Venta'];

// Validate before sending
if (!validEstados.includes(data.estado)) {
  throw new Error('Invalid estado value');
}
Error:
{
  "success": false,
  "error": "Required field missing: ciudad"
}
Cause: Omitted a required field when creating a propertyRequired fields: pais, ciudad, direccion, ambientes, metros_cuadrados, precio, tipo_contratacion, estadoSolution:
const requiredFields = [
  'pais', 'ciudad', 'direccion', 'ambientes',
  'metros_cuadrados', 'precio', 'tipo_contratacion', 'estado'
];

// Validate all required fields are present
for (const field of requiredFields) {
  if (!(field in data)) {
    throw new Error(`Missing required field: ${field}`);
  }
}
Error:
{
  "success": false,
  "error": "Invalid input: codigo_id must be exactly 6 characters"
}
Cause: Provided a codigo_id that’s not exactly 6 charactersSolution:
if (data.codigo_id && data.codigo_id.length !== 6) {
  throw new Error('codigo_id must be exactly 6 characters');
}
Error:
{
  "success": false,
  "error": "Invalid input: precio must be a number"
}
Cause: Sent a number field as a stringSolution:
// Wrong
{ "precio": "100000" }

// Correct
{ "precio": 100000 }

// Convert if needed
const data = {
  precio: parseFloat(priceString),
  ambientes: parseInt(roomsString, 10)
};
Error:
{
  "success": false,
  "error": "No está permitido modificar el código identificador de la propiedad."
}
Cause: Tried to change the codigo_id in a PATCH requestSolution:
// Don't include codigo_id in PATCH requests
const updateData = { ...data };
delete updateData.codigo_id;

await fetch(`${baseURL}/api/propiedades/${id}`, {
  method: 'PATCH',
  body: JSON.stringify(updateData)
});

401 Unauthorized

Returned when authentication is missing or invalid. Error:
{
  "error": "Unauthorized"
}
Causes:
  • No Authorization header provided
  • Invalid credentials
  • Malformed Authorization header
Solution:
// Verify credentials first
async function verifyCredentials(username, password) {
  const credentials = btoa(`${username}:${password}`);
  
  const response = await fetch(
    'https://idforideas-1.jamrdev.com.ar/api/auth/verify',
    {
      headers: {
        'Authorization': `Basic ${credentials}`
      }
    }
  );
  
  if (!response.ok) {
    throw new Error('Invalid credentials');
  }
  
  return credentials;
}

// Use verified credentials
try {
  const credentials = await verifyCredentials('admin', 'password');
  // Now use credentials for other requests
} catch (error) {
  console.error('Authentication failed:', error);
}

404 Not Found

Returned when the requested resource doesn’t exist. Error:
{
  "error": "Propiedad no encontrada"
}
Or for updates:
{
  "success": false,
  "error": "Propiedad no encontrada"
}
Causes:
  • Property ID doesn’t exist
  • Property was deleted
  • Typo in the ID
Solution:
async function getProperty(id) {
  const response = await fetch(
    `https://idforideas-1.jamrdev.com.ar/api/propiedades/${id}`
  );
  
  if (response.status === 404) {
    throw new Error(`Property ${id} not found`);
  }
  
  if (!response.ok) {
    throw new Error(`HTTP error ${response.status}`);
  }
  
  return response.json();
}

try {
  const property = await getProperty('ZN1001');
  console.log(property);
} catch (error) {
  console.error('Failed to fetch property:', error.message);
}

409 Conflict

Returned when creating a property with a codigo_id that already exists. Error:
{
  "success": false,
  "error": "El código ZN1001 ya existe."
}
Solution:
async function createProperty(data) {
  const response = await fetch(
    'https://idforideas-1.jamrdev.com.ar/api/propiedades',
    {
      method: 'POST',
      headers: {
        'Authorization': `Basic ${credentials}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    }
  );
  
  if (response.status === 409) {
    // ID already exists - let API generate one
    const dataWithoutId = { ...data };
    delete dataWithoutId.codigo_id;
    
    return createProperty(dataWithoutId);
  }
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error || 'Failed to create property');
  }
  
  return response.json();
}

Error Handling Patterns

Basic Error Handler

async function apiRequest(url, options = {}) {
  try {
    const response = await fetch(url, options);
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.error || `HTTP ${response.status}`);
    }
    
    return response.json();
  } catch (error) {
    console.error('API request failed:', error);
    throw error;
  }
}

Detailed Error Handler

class APIError extends Error {
  constructor(message, status, details) {
    super(message);
    this.name = 'APIError';
    this.status = status;
    this.details = details;
  }
}

async function apiRequest(url, options = {}) {
  let response;
  
  try {
    response = await fetch(url, options);
  } catch (error) {
    throw new APIError('Network error', 0, error.message);
  }
  
  const data = await response.json();
  
  if (!response.ok) {
    throw new APIError(
      data.error || 'Request failed',
      response.status,
      data
    );
  }
  
  return data;
}

// Usage
try {
  const result = await apiRequest('/api/propiedades', { method: 'POST', ... });
} catch (error) {
  if (error instanceof APIError) {
    switch (error.status) {
      case 400:
        console.error('Validation error:', error.message);
        break;
      case 401:
        console.error('Authentication failed');
        // Redirect to login
        break;
      case 404:
        console.error('Not found:', error.message);
        break;
      case 409:
        console.error('Conflict:', error.message);
        // Retry without custom ID
        break;
      default:
        console.error('Unexpected error:', error);
    }
  } else {
    console.error('Unknown error:', error);
  }
}

Retry Logic

async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      
      // Don't retry client errors (4xx)
      if (response.status >= 400 && response.status < 500) {
        const error = await response.json();
        throw new Error(error.error || 'Client error');
      }
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      
      return response.json();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      // Wait before retrying (exponential backoff)
      await new Promise(resolve => 
        setTimeout(resolve, Math.pow(2, i) * 1000)
      );
    }
  }
}

Python Error Handler

import requests
from typing import Dict, Any

class APIError(Exception):
    def __init__(self, message: str, status_code: int, details: Any = None):
        super().__init__(message)
        self.status_code = status_code
        self.details = details

def api_request(url: str, method: str = 'GET', **kwargs) -> Dict[str, Any]:
    """Make an API request with error handling"""
    try:
        response = requests.request(method, url, **kwargs)
        
        if not response.ok:
            error_data = response.json()
            error_msg = error_data.get('error', f'HTTP {response.status_code}')
            raise APIError(error_msg, response.status_code, error_data)
        
        return response.json()
    
    except requests.RequestException as e:
        raise APIError('Network error', 0, str(e))

# Usage
try:
    result = api_request(
        'https://idforideas-1.jamrdev.com.ar/api/propiedades',
        method='POST',
        json=data,
        auth=('admin', 'password')
    )
except APIError as e:
    if e.status_code == 400:
        print(f'Validation error: {e}')
    elif e.status_code == 401:
        print('Authentication failed')
    elif e.status_code == 404:
        print(f'Not found: {e}')
    elif e.status_code == 409:
        print(f'Conflict: {e}')
        # Retry without custom ID
    else:
        print(f'Unexpected error: {e}')

Validation Before Sending

Prevent errors by validating data client-side:
function validateProperty(data) {
  const errors = [];
  
  // Required fields
  const required = [
    'pais', 'ciudad', 'direccion', 'ambientes',
    'metros_cuadrados', 'precio', 'tipo_contratacion', 'estado'
  ];
  
  for (const field of required) {
    if (!(field in data) || data[field] === null || data[field] === '') {
      errors.push(`Missing required field: ${field}`);
    }
  }
  
  // codigo_id length
  if (data.codigo_id && data.codigo_id.length !== 6) {
    errors.push('codigo_id must be exactly 6 characters');
  }
  
  // Enum values
  const validEstados = ['Disponible', 'Reservado', 'Alquilado', 'Vendido'];
  if (data.estado && !validEstados.includes(data.estado)) {
    errors.push(`estado must be one of: ${validEstados.join(', ')}`);
  }
  
  const validTipos = ['Alquiler', 'Venta'];
  if (data.tipo_contratacion && !validTipos.includes(data.tipo_contratacion)) {
    errors.push(`tipo_contratacion must be one of: ${validTipos.join(', ')}`);
  }
  
  // Number types
  if (data.ambientes && typeof data.ambientes !== 'number') {
    errors.push('ambientes must be a number');
  }
  
  if (data.metros_cuadrados && typeof data.metros_cuadrados !== 'number') {
    errors.push('metros_cuadrados must be a number');
  }
  
  if (data.precio && typeof data.precio !== 'number') {
    errors.push('precio must be a number');
  }
  
  return errors;
}

// Usage
const errors = validateProperty(data);
if (errors.length > 0) {
  console.error('Validation errors:', errors);
  // Show errors to user
} else {
  // Send to API
}

Best Practices

1

Validate client-side first

Check data format and required fields before making API calls to reduce errors.
2

Handle all status codes

Implement handlers for 400, 401, 404, and 409 status codes.
3

Show user-friendly messages

Translate API errors into clear messages for your users.
4

Log errors for debugging

Keep detailed error logs for troubleshooting.
5

Don't retry authentication errors

If you get a 401, the credentials are wrong - don’t retry automatically.

Next Steps

Validation Rules

Complete validation rules reference

Creating Properties

Learn about property creation

Authentication

Set up authentication correctly

API Reference

Browse the complete API reference

Build docs developers (and LLMs) love