Skip to content

ErrorTypes Enumeration | Vue Router

ErrorTypes is an enumeration that defines various error types that can occur during router operations. This enum helps categorize and handle different types of routing errors consistently. 🚨

📋 Enum Definition

typescript
enum ErrorTypes {
  MATCHER_NOT_FOUND = 1,
  NAVIGATION_GUARD_REDIRECT = 2,
  NAVIGATION_ABORTED = 4,
  NAVIGATION_CANCELLED = 8,
  NAVIGATION_DUPLICATED = 16
}

🎯 Purpose and Usage

The ErrorTypes enumeration provides a standardized way to identify and handle different categories of routing errors. Each error type corresponds to specific failure scenarios in the routing system.

Key Benefits:

  • Error Categorization - Classifies errors into meaningful categories
  • Consistent Handling - Enables uniform error handling patterns
  • Debugging Support - Helps identify root causes of routing issues
  • Type Safety - Provides TypeScript support for error handling

🔍 Enumeration Members

MATCHER_NOT_FOUND - Route Matcher Error

Value: 1

This error occurs when the router cannot find a matching route for the requested path. It typically indicates that the route configuration is missing or incorrect.

Common Scenarios:

  • Navigating to a non-existent route
  • Route configuration errors
  • Dynamic route parameter mismatches

Example:

typescript
try {
  await router.push('/non-existent-route')
} catch (error) {
  if (error.type === ErrorTypes.MATCHER_NOT_FOUND) {
    console.error('Route not found:', error.to.path)
    // Handle 404 scenario
    showNotFoundPage()
  }
}

Value: 2

This error type represents redirects initiated by navigation guards. While technically an "error" in the navigation flow, it's a normal part of guard-based redirects.

Common Scenarios:

  • Authentication guards redirecting to login
  • Permission-based redirects
  • Conditional routing logic

Example:

typescript
router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !isAuthenticated()) {
    // This creates a NAVIGATION_GUARD_REDIRECT error
    return '/login'
  }
})

// Handling guard redirects
router.push('/protected').catch(error => {
  if (error.type === ErrorTypes.NAVIGATION_GUARD_REDIRECT) {
    console.log('Redirected by guard to:', error.to.path)
    // This is expected behavior, not an actual error
  }
})

These values correspond to the NavigationFailureType enumeration and represent specific navigation failure scenarios:

  • NAVIGATION_ABORTED (4) - Navigation was aborted by a guard
  • NAVIGATION_CANCELLED (8) - Navigation was cancelled by a subsequent navigation
  • NAVIGATION_DUPLICATED (16) - Navigation to the current location was attempted

Note: These are maintained for backward compatibility but NavigationFailureType should be used for navigation-specific errors.

💡 Practical Error Handling

Comprehensive Error Handler

typescript
function setupGlobalErrorHandler(router: Router) {
  router.onError((error) => {
    console.group('Router Error Details')
    console.log('Error type:', error.type)
    console.log('Error message:', error.message)
    console.log('Target route:', error.to)
    console.log('From route:', error.from)
    console.groupEnd()
    
    // Handle different error types
    switch (error.type) {
      case ErrorTypes.MATCHER_NOT_FOUND:
        handleRouteNotFound(error)
        break
        
      case ErrorTypes.NAVIGATION_GUARD_REDIRECT:
        handleGuardRedirect(error)
        break
        
      case ErrorTypes.NAVIGATION_ABORTED:
      case ErrorTypes.NAVIGATION_CANCELLED:
      case ErrorTypes.NAVIGATION_DUPLICATED:
        handleNavigationFailure(error)
        break
        
      default:
        handleUnknownError(error)
    }
  })
}

Route-Specific Error Handling

typescript
async function navigateSafely(targetRoute: string) {
  try {
    await router.push(targetRoute)
    console.log('Navigation completed successfully')
  } catch (error) {
    if (error.type === ErrorTypes.MATCHER_NOT_FOUND) {
      // Fallback to a known route
      await router.push('/fallback')
      showErrorMessage(`Route ${targetRoute} not found`)
    } else if (error.type === ErrorTypes.NAVIGATION_ABORTED) {
      // Handle aborted navigation (e.g., permission denied)
      showAccessDeniedMessage()
    } else {
      // Generic error handling
      console.error('Navigation error:', error)
      showGenericError()
    }
  }
}

🔧 Advanced Error Management

Error Recovery Strategies

typescript
class ErrorRecoveryService {
  private retryAttempts = new Map<string, number>()
  
  async navigateWithRetry(to: RouteLocationRaw, maxRetries = 3): Promise<void> {
    const routeKey = JSON.stringify(to)
    let attempts = this.retryAttempts.get(routeKey) || 0
    
    try {
      await router.push(to)
      this.retryAttempts.delete(routeKey) // Clear on success
    } catch (error) {
      attempts++
      this.retryAttempts.set(routeKey, attempts)
      
      if (attempts <= maxRetries) {
        console.log(`Retry attempt ${attempts} for route:`, to)
        await this.delay(1000 * attempts) // Exponential backoff
        return this.navigateWithRetry(to, maxRetries)
      } else {
        this.handleMaxRetriesExceeded(error, to)
      }
    }
  }
  
  private handleMaxRetriesExceeded(error: any, to: RouteLocationRaw) {
    switch (error.type) {
      case ErrorTypes.MATCHER_NOT_FOUND:
        this.handlePermanentRouteError(to)
        break
        
      case ErrorTypes.NAVIGATION_ABORTED:
        this.showPermanentAccessDenied()
        break
        
      default:
        this.showGenericRetryError()
    }
  }
}

Error Analytics and Reporting

typescript
class ErrorAnalytics {
  trackRouterError(error: any, context: NavigationContext) {
    const errorData = {
      type: error.type,
      message: error.message,
      route: context.to.path,
      timestamp: Date.now(),
      userAgent: navigator.userAgent,
      // Additional context
      fromRoute: context.from?.path,
      navigationType: context.navigationType
    }
    
    // Send to analytics service
    analytics.track('router_error', errorData)
    
    // Log for debugging
    if (process.env.NODE_ENV === 'development') {
      console.error('Router Error:', errorData)
    }
  }
  
  setupErrorTracking(router: Router) {
    router.onError((error) => {
      this.trackRouterError(error, {
        to: error.to,
        from: error.from,
        navigationType: 'programmatic'
      })
    })
  }
}

🚨 Important Considerations

Error Type Compatibility

typescript
import { ErrorTypes, NavigationFailureType } from 'vue-router'

// ✅ Correct - use appropriate enum for the context
if (error.type === ErrorTypes.MATCHER_NOT_FOUND) {
  // Handle route matching errors
}

if (error.type === NavigationFailureType.ABORTED) {
  // Handle navigation failures
}

// ❌ Avoid - mixing error type systems
if (error.type === 4) {
  // Use named constants instead of magic numbers
}

// ✅ Better - use named constants
if (error.type === NavigationFailureType.ABORTED) {
  // Clear intent
}

Error Object Structure

typescript
// Typical error object structure
interface RouterError {
  type: ErrorTypes | NavigationFailureType
  message: string
  to: RouteLocationNormalized
  from?: RouteLocationNormalized
  // Additional properties may be present depending on error type
}

// Example error handling with type checking
function handleRouterError(error: unknown) {
  if (isRouterError(error)) {
    switch (error.type) {
      case ErrorTypes.MATCHER_NOT_FOUND:
        // Handle specific error type
        break
      // ... other cases
    }
  } else {
    // Handle non-router errors
    console.error('Non-router error:', error)
  }
}

function isRouterError(error: unknown): error is RouterError {
  return typeof error === 'object' && error !== null && 'type' in error
}

📚 Best Practices

1. Graceful Error Handling

typescript
// Instead of letting errors crash the app
router.push('/target').catch(error => {
  // Provide user-friendly feedback based on error type
  if (error.type === ErrorTypes.MATCHER_NOT_FOUND) {
    showNotFoundMessage()
  } else if (error.type === ErrorTypes.NAVIGATION_ABORTED) {
    showAccessDeniedMessage()
  } else {
    showGenericErrorMessage()
  }
})

2. Development vs Production

typescript
function setupErrorHandling(router: Router) {
  if (process.env.NODE_ENV === 'development') {
    // Detailed error logging for development
    router.onError((error) => {
      console.error('Router Error Details:', {
        type: error.type,
        message: error.message,
        stack: error.stack,
        to: error.to,
        from: error.from
      })
    })
  } else {
    // User-friendly error handling for production
    router.onError((error) => {
      // Send to error reporting service
      errorReporting.captureException(error)
      // Show user-friendly message
      showErrorToast('Navigation failed. Please try again.')
    })
  }
}

3. Error Recovery Patterns

typescript
class NavigationRecovery {
  private fallbackRoutes = new Map<string, string>()
  
  constructor(private router: Router) {
    this.setupFallbackRoutes()
  }
  
  private setupFallbackRoutes() {
    // Define fallback routes for common errors
    this.fallbackRoutes.set('/admin', '/access-denied')
    this.fallbackRoutes.set('/premium', '/upgrade-required')
  }
  
  async navigateWithFallback(to: RouteLocationRaw) {
    try {
      await router.push(to)
    } catch (error) {
      if (error.type === ErrorTypes.NAVIGATION_ABORTED) {
        const fallback = this.fallbackRoutes.get(typeof to === 'string' ? to : to.path)
        if (fallback) {
          await router.push(fallback)
        } else {
          this.handleGenericError(error)
        }
      } else {
        this.handleGenericError(error)
      }
    }
  }
}

💡 Pro Tip: While ErrorTypes provides valuable error categorization, most applications should focus on handling the specific error scenarios that matter to their users rather than trying to handle every possible error type.

🚀 Vue Router - 让前端路由变得简单而强大 | 构建现代化单页应用的最佳选择