Map Debugging — Common Issues and Solutions

Why Debugging Matters

Map applications have many moving parts — map tiles, markers, popups, API calls, authentication, and spatial queries. When something breaks, knowing where to look saves hours of frustration.

Why this matters for your career:

  • Debugging is the most common activity in software development
  • Map-specific issues (tiles, projections, coordinates) require specialized knowledge
  • Systematic debugging separates junior from senior developers
  • Understanding common failure modes helps you prevent them in the first place

Common Map Issues and Solutions

1. Blank Map (No Tiles)

Symptoms: Map container is visible but shows only a gray background.

Causes and fixes:

| Cause | Fix | |-------|-----| | No tile layer added | Add L.tileLayer(...).addTo(map) | | Wrong tile URL | Check the tile server URL is correct and accessible | | API key missing | Some tile providers require an API key | | HTTPS mixed content | If your site is HTTPS, tile URL must also be HTTPS | | CORS blocked | Tile server must allow CORS or use a proxy | | Ad blocker | Some ad blockers block tile servers — test in incognito mode |

// Fix: Check tile layer configuration
const tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  maxZoom: 19,
  attribution: '© OpenStreetMap contributors'
});

// Verify the tile URL works by testing in browser:
// https://a.tile.openstreetmap.org/10/1024/768.png

tileLayer.on('tileerror', function(error) {
  console.error('Tile failed to load:', error);
});

tileLayer.addTo(map);

2. Markers Not Showing

Symptoms: Markers are not visible on the map.

| Cause | Fix | |-------|-----| | Markers added before map initialization | Create map first, then add markers | | Wrong coordinates (lat/lng swapped) | Leaflet uses [lat, lng] — NOT [lng, lat] | | Markers outside map bounds | Check marker coordinates are within the viewable area | | Marker layer not added to map | Call marker.addTo(map) | | Cluster group not added to map | Call mcg.addTo(map) for cluster groups | | CSS overflow hidden | Check the map container CSS |

// Fix: Proper marker creation
const marker = L.marker([25.033, 121.565]);  // [latitude, longitude]
marker.addTo(map);

// Verify coordinates
console.log('Marker position:', marker.getLatLng());

// Check map bounds contain the marker
const bounds = map.getBounds();
console.log('Marker in bounds:', bounds.contains(marker.getLatLng()));

3. Wrong Coordinates

Symptoms: Markers appear in unexpected locations (e.g., in the ocean).

| Cause | Fix | |-------|-----| | Lat/lng swapped | In Leaflet, it's [lat, lng]. In APIs, JSON often uses {lng, lat} | | Wrong coordinate system | GPS uses WGS84 (EPSG:4326). Some data uses other SRIDs | | Sign error | Taiwan is north of equator (lat > 0) and east of Greenwich (lng > 0) | | Copy-paste from wrong source | Verify coordinates from a reliable source |

// Correct: [latitude, longitude]
// Taiwan example: [25.033, 121.565]

function parseCoordinates(input) {
  const [lat, lng] = input.split(',').map(Number);

  if (isNaN(lat) || isNaN(lng)) {
    throw new Error(`Invalid coordinates: ${input}`);
  }

  if (lat < -90 || lat > 90) {
    throw new Error(`Latitude must be between -90 and 90: ${lat}`);
  }

  if (lng < -180 || lng > 180) {
    throw new Error(`Longitude must be between -180 and 180: ${lng}`);
  }

  return { lat, lng };
}

4. CORS Errors

Symptoms: Browser console shows CORS errors when fetching data.

| Cause | Fix | |-------|-----| | API and frontend on different origins | Enable CORS on the API server | | Supabase requests blocked | Allow the frontend origin in Supabase settings | | Tile server doesn't support CORS | Use a CORS proxy or switch tile providers |

// Supabase CORS configuration (in Supabase dashboard)
// Settings → API → CORS → Add your frontend domain
// e.g., https://mycampingmap.vercel.app

5. Performance Issues

Symptoms: Map is slow, laggy, or crashes.

| Cause | Fix | |-------|-----| | Too many markers without clustering | Add marker clustering | | No spatial index on database | Add GIST index on location column | | Loading all data at once | Load only visible bounds | | Large tile set at low zoom | Limit min/max zoom levels | | Too many popups open simultaneously | Only show one popup at a time | | Memory leak from repeated marker creation | Reuse markers, clear old ones first |

// Performance checklist
// ✅ Marker clustering installed
// ✅ Spatial index on database
// ✅ Bounds-based loading
// ✅ Zoom level limits (minZoom: 6, maxZoom: 18)
// ✅ Single popup at a time
// ✅ Markers cleared when out of bounds
// ✅ Chunked loading for large datasets
// ✅ Debounced API calls on map movement

Debugging Tools

| Tool | Purpose | |------|---------| | Browser DevTools Console | See JavaScript errors and warnings | | Network tab | Check API calls, tile loading, response times | | map.on('tileerror', ...) | Detect failed tile loads | | Leaflet debug plugin | Visualize layers and bounds | | PostGIS EXPLAIN ANALYZE | Debug slow spatial queries | | Supabase Dashboard | Query logs, error rates, API calls | | Lighthouse | Performance audit and suggestions | | GeoJSON.io | Validate GeoJSON data |

Debugging Leaflet Events

// Log all map events
const events = ['click', 'dblclick', 'moveend', 'zoomend', 'dragstart', 'dragend'];
events.forEach(event => {
  map.on(event, (e) => console.log(`Event: ${event}`, e));
});

// Log tile loading events
map.on('load', () => console.log('Map fully loaded'));
map.on('tileload', (e) => console.log('Tile loaded:', e.url));
map.on('tileerror', (e) => console.error('Tile error:', e.url));

// Log layer events
map.on('layeradd', (e) => console.log('Layer added:', e.layer));
map.on('layerremove', (e) => console.log('Layer removed:', e.layer));

Debugging Spatial Queries

-- Check if PostGIS is using the spatial index
EXPLAIN ANALYZE
SELECT * FROM campsites
WHERE location && ST_MakeEnvelope(121.0, 24.5, 122.0, 25.5, 4326);

-- Look for "Index Scan" in the output — not "Seq Scan"
-- If you see "Seq Scan", your GIST index is missing or not being used

-- Verify the index exists
SELECT indexname, indexdef FROM pg_indexes
WHERE tablename = 'campsites';

Common Supabase Issues

| Issue | Solution | |-------|----------| | Row Level Security (RLS) blocks queries | Enable RLS with proper policies or disable for development | | CORS errors from Supabase | Add your domain in Supabase CORS settings | | Rate limiting (429) | Add client-side caching, reduce request frequency | | Large response payload | Add pagination, select only needed columns | | WebSocket connection drops | Check Supabase status page, reconnect on disconnect |

Browser-Specific Issues

| Browser | Known Issue | Workaround | |---------|-------------|------------| | Safari iOS | Geolocation requires HTTPS | Use HTTPS or development fallback | | Chrome | Mixed content warnings for HTTP tiles | Use HTTPS tile URLs | | Firefox | CORS strict mode | Ensure proper CORS headers | | Mobile browsers | touch-action: manipulation needed | Add CSS rule for Leaflet container |

/* Fix mobile scroll interference */
.leaflet-container {
  touch-action: manipulation;
}

Debugging Checklist

  1. ✅ Check browser console for errors
  2. ✅ Verify map container has a defined height (CSS)
  3. ✅ Confirm tile layer URL is correct and accessible
  4. ✅ Check coordinates are in [lat, lng] order
  5. ✅ Verify markers are within the initial map bounds
  6. ✅ Check for CORS errors in API calls
  7. ✅ Monitor network tab for failed requests
  8. ✅ Test in incognito/private mode (eliminates extension interference)
  9. ✅ Check database spatial index exists
  10. ✅ Verify Supabase RLS policies if queries return empty

Summary

Debugging map applications requires a systematic approach — check the console first, verify coordinates, inspect network requests, and test without extensions. Most issues fall into a few categories: wrong coordinates, missing layers, CORS errors, or performance problems.

Key takeaways:

  • Always use [latitude, longitude] order in Leaflet
  • Check tile URLs are HTTPS (avoid mixed content)
  • Verify map container has explicit height in CSS
  • Use the browser Network tab to inspect failed requests
  • Add marker clustering before performance becomes an issue
  • Check spatial indexes for slow database queries
  • Test in incognito mode to rule out extension interference
  • Use EXPLAIN ANALYZE to verify index usage
  • Add tileerror event listener to detect failed tiles
  • Use touch-action: manipulation CSS for mobile Leaflet

What's Next: Search & Autocomplete

The next chapter covers search and autocomplete — helping users find campsites by name, location, or amenity with an efficient search interface.

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!