Troubleshooting
Common issues and solutions when working with Hyperbasis.
Relocalization Issues
Anchors Don't Reappear After Restart
Symptoms: You saved anchors, but when you relaunch the app, nothing shows up in the AR view.
Possible causes:
- •
World map wasn't saved properly
- •Check that tracking state was
.normalbefore saving - •Ensure
arSession.currentWorldMapsucceeded
- •Check that tracking state was
- •
Relocalization hasn't completed
- •AR needs time to recognize the space
- •Move the device around to help it match features
- •
Environment changed significantly
- •Furniture moved, lighting changed drastically
- •ARKit can't match the stored features
Solutions:
// 1. Verify world map was saved
let spaces = try await storage.loadAllSpaces()
print("Saved spaces: \(spaces.count)")
// 2. Check relocalization status
func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
switch camera.trackingState {
case .normal:
print("Relocalized! Now load anchors")
Task { await loadAnchors() }
case .limited(let reason):
print("Limited tracking: \(reason)")
case .notAvailable:
print("Tracking not available")
}
}
// 3. Help user understand what's happening
if camera.trackingState == .limited(.relocalizing) {
showMessage("Move your phone around to help recognize the space")
}Anchors Appear in Wrong Positions
Symptoms: Anchors load but they're offset from where they were placed.
Possible causes:
- •Partial relocalization - ARKit matched some features but not perfectly
- •World map captured too early - Not enough features were scanned
- •Different starting position - User started AR session in a different spot
Solutions:
// Wait for stable tracking before loading anchors
func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
guard camera.trackingState == .normal else { return }
// Add small delay to ensure stable relocalization
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
Task { await self.loadAnchors() }
}
}Prevention:
- •Save world map only when tracking is
.normal - •Encourage users to scan more of the environment
- •Save world map after placing several anchors (more features)
"Relocalization Failed" or Never Completes
Symptoms: AR session stays in .limited(.relocalizing) state indefinitely.
Possible causes:
- •Environment changed too much - Room rearranged, different time of day
- •Wrong room - User is in a different physical space
- •Corrupted world map data
Solutions:
// Implement a timeout and fallback
class RelocalizationManager {
private var relocalizationTimer: Timer?
func startRelocalization(with worldMap: ARWorldMap) {
let config = ARWorldTrackingConfiguration()
config.initialWorldMap = worldMap
arSession.run(config, options: [.resetTracking])
// Timeout after 30 seconds
relocalizationTimer = Timer.scheduledTimer(withTimeInterval: 30, repeats: false) { [weak self] _ in
self?.handleRelocalizationTimeout()
}
}
func handleRelocalizationTimeout() {
// Offer to start fresh
showAlert(
title: "Can't Recognize Space",
message: "The room may have changed. Start fresh?",
actions: [
("Try Again", { self.retryRelocalization() }),
("Start New Space", { self.createNewSpace() })
]
)
}
}Storage Issues
"File Not Found" Errors
Symptoms: loadSpace(id:) or loadAnchor(id:) returns nil or throws an error.
Possible causes:
- •ID mismatch - Using wrong UUID
- •Storage cleared -
clearLocalStorage()was called - •App reinstalled - Local storage is deleted with the app
Solutions:
// Always handle the nil case
if let space = try await storage.loadSpace(id: savedId) {
// Use space
} else {
// Space not found - create new one
print("Space \(savedId) not found, creating new space")
}
// Check what's actually in storage
let allSpaces = try await storage.loadAllSpaces()
print("Available spaces: \(allSpaces.map { $0.id })")Storage Size Growing Too Large
Symptoms: App using significant disk space over time.
Solutions:
// Check storage size
let size = try storage.localStorageSize()
print("Storage: \(ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file))")
// Purge old deleted anchors
let thirtyDaysAgo = Calendar.current.date(byAdding: .day, value: -30, to: Date())!
try await storage.purgeDeletedAnchors(before: thirtyDaysAgo)
// Delete unused spaces
for space in try await storage.loadAllSpaces() {
let anchors = try await storage.loadAnchors(spaceId: space.id)
if anchors.isEmpty && space.updatedAt < thirtyDaysAgo {
try await storage.deleteSpace(id: space.id)
}
}Cloud Sync Issues
Sync Fails Silently
Symptoms: Data isn't appearing on other devices, no errors thrown.
Possible causes:
- •Cloud not configured - Using
.localOnlybackend - •Network issues - Device is offline
- •Supabase credentials wrong - Check URL and anon key
Solutions:
// Check if cloud is enabled
print("Cloud enabled: \(storage.isCloudEnabled)")
print("Pending operations: \(storage.pendingOperationCount)")
// Force a sync and handle errors explicitly
do {
try await storage.sync()
print("Sync completed")
} catch HBStorageError.cloudNotConfigured {
print("Cloud not configured - using local only")
} catch HBStorageError.networkError(let underlying) {
print("Network error: \(underlying)")
} catch {
print("Sync failed: \(error)")
}Pending Operations Stuck
Symptoms: pendingOperationCount keeps growing, sync not completing.
Solutions:
// Check pending count
if storage.pendingOperationCount > 10 {
print("Warning: \(storage.pendingOperationCount) operations pending")
// Try syncing when network is available
let monitor = NWPathMonitor()
monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
Task { try? await storage.sync() }
}
}
monitor.start(queue: .global())
}Performance Issues
Slow World Map Loading
Symptoms: arWorldMap() takes several seconds to return.
Cause: Deserialization of large world maps is CPU-intensive.
Solutions:
// Load on background thread, apply on main
Task.detached(priority: .userInitiated) {
let worldMap = try space.arWorldMap()
await MainActor.run {
let config = ARWorldTrackingConfiguration()
config.initialWorldMap = worldMap
arSession.run(config)
}
}
// Show loading indicator
isLoading = true
defer { isLoading = false }Memory Warnings When Saving
Symptoms: App receives memory warnings during storage.save(space).
Cause: Large world maps (30-50MB) require significant memory during serialization.
Solutions:
// Check world map size before saving
let sizeInMB = Double(space.worldMapSize) / 1_000_000
if sizeInMB > 40 {
print("Warning: Large world map (\(space.worldMapSizeFormatted))")
}
// Use compression (enabled by default)
let config = HBStorageConfig(compression: .balanced) // ~40% size reduction
let storage = HBStorage(config: config)Common Error Messages
| Error | Meaning | Solution |
|---|---|---|
HBSpaceError.serializationFailed | ARWorldMap couldn't be archived | Ensure ARWorldMap is valid, try recapturing |
HBSpaceError.deserializationFailed | Stored data is corrupted | Delete the space and recapture |
HBAnchorError.invalidTransform | Transform array isn't 16 floats | Check transform creation code |
HBStorageError.notFound | Requested item doesn't exist | Verify ID, check if storage was cleared |
HBStorageError.cloudNotConfigured | Trying to sync without cloud setup | Configure Supabase backend or use local only |
Debug Utilities
Inspect Local Storage
// Print all stored data
func debugStorage() async throws {
let spaces = try await storage.loadAllSpaces()
print("=== Spaces (\(spaces.count)) ===")
for space in spaces {
print(" \(space.id): \(space.name ?? "unnamed") (\(space.worldMapSizeFormatted))")
let anchors = try await storage.loadAnchors(spaceId: space.id, includeDeleted: true)
print(" Anchors: \(anchors.filter { !$0.isDeleted }.count) active, \(anchors.filter { $0.isDeleted }.count) deleted")
}
print("\nTotal size: \(ByteCountFormatter.string(fromByteCount: Int64(try storage.localStorageSize()), countStyle: .file))")
}Reset Everything
// Nuclear option - clear all data and start fresh
func resetAll() throws {
try storage.clearLocalStorage()
print("All local data cleared")
}clearLocalStorage() permanently deletes all spaces and anchors. This cannot be undone.
Next Steps
- •Error Handling - Detailed error types and handling patterns
- •AR Session - Proper session management
- •Local Storage - Understanding the storage system