This error occurs in React Router when a dynamic route parameter receives an empty string or undefined value instead of a valid non-empty string. It typically happens when constructing navigation paths programmatically or when route parameters are not properly validated.
This error is thrown by React Router when you attempt to navigate to or define a route with a dynamic segment that contains an empty string. Dynamic route segments (parameters) in React Router must always be non-empty strings to ensure proper route matching and parameter extraction. React Router uses dynamic segments in route paths like `/users/:userId` where `:userId` is the parameter. When you navigate to such routes programmatically or render links, the parameter value must be a valid, non-empty string. Empty strings, `null`, or `undefined` values will trigger this error because they create invalid route paths that cannot be properly matched or parsed. This validation exists to maintain route integrity and prevent silent failures where a route might appear to work but actually match incorrectly or fail to extract parameters properly.
Add validation to ensure route parameters are non-empty before using them in navigation:
import { useNavigate } from 'react-router-dom';
function UserProfile({ userId }) {
const navigate = useNavigate();
const handleNavigate = () => {
// Validate parameter before navigation
if (!userId || userId.trim() === '') {
console.error('Invalid userId');
return;
}
navigate(`/users/${userId}`);
};
return <button onClick={handleNavigate}>View Profile</button>;
}This prevents empty values from reaching the router.
Conditionally render Link components or disable them when parameters are invalid:
import { Link } from 'react-router-dom';
function UserCard({ user }) {
// Guard against missing or invalid IDs
if (!user?.id) {
return <span className="text-muted">User ID unavailable</span>;
}
return (
<Link to={{`/users/${user.id}`}}>
View Profile
</Link>
);
}You can also disable the link:
function UserCard({ user }) {
const userId = user?.id;
const isValidId = userId && userId.trim() !== '';
return isValidId ? (
<Link to={`/users/${userId}`}>View Profile</Link>
) : (
<span className="disabled-link">View Profile</span>
);
}Provide fallback values or make route segments optional when appropriate:
// Option 1: Default value
function ProductPage({ productId = 'featured' }) {
const navigate = useNavigate();
const handleNavigate = () => {
// productId will never be empty
navigate(`/products/${productId}`);
};
}
// Option 2: Optional route segment
// Define route with optional parameter
<Route path="/products/:id?" element={<ProductList />} />
// In component, handle missing parameter
function ProductList() {
const { id } = useParams();
if (!id) {
return <AllProducts />;
}
return <ProductDetail id={id} />;
}Ensure data is loaded and valid before rendering components with dynamic routes:
function UserDashboard() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchUsers().then(data => {
setUsers(data);
setLoading(false);
});
}, []);
if (loading) {
return <LoadingSpinner />;
}
return (
<div>
{users.map(user => {
// Filter out invalid entries
if (!user.id) {
console.warn('User missing ID:', user);
return null;
}
return (
<Link key={user.id} to={`/users/${user.id}`}>
{user.name}
</Link>
);
})}
</div>
);
}Use TypeScript to enforce non-empty strings at compile time:
import { useNavigate, useParams } from 'react-router-dom';
// Type guard for non-empty strings
type NonEmptyString = string & { __brand: 'NonEmptyString' };
function isNonEmptyString(value: unknown): value is NonEmptyString {
return typeof value === 'string' && value.trim().length > 0;
}
// Helper function for safe navigation
function useSafeNavigate() {
const navigate = useNavigate();
return (path: string, params: Record<string, unknown>) => {
const validatedParams: Record<string, string> = {};
for (const [key, value] of Object.entries(params)) {
if (!isNonEmptyString(value)) {
throw new Error(`Parameter '${key}' must be a non-empty string`);
}
validatedParams[key] = value;
}
// Build path with validated params
let finalPath = path;
for (const [key, value] of Object.entries(validatedParams)) {
finalPath = finalPath.replace(`:${key}`, value);
}
navigate(finalPath);
};
}
// Usage
function MyComponent({ userId }: { userId: string }) {
const safeNavigate = useSafeNavigate();
const handleClick = () => {
safeNavigate('/users/:userId', { userId });
};
}React Router v6 vs v7: This error validation was strengthened in React Router v6 and later versions. Earlier versions (v5 and below) were more permissive but could lead to silent failures or incorrect route matching.
Optional Parameters: You can make route segments optional by adding ? to the parameter definition: /users/:userId?. This allows the parameter to be omitted entirely from the URL, but if provided, it must still be non-empty.
Splat Routes: For catch-all routes using *, React Router will parse the star parameter as an empty string if no segments match. Be prepared to handle empty strings when using splat routes: <Route path="/files/*" />
Type-Safe Routing: Consider using libraries like react-router-typesafe-routes or @tanstack/react-router for additional type safety and validation at compile time. These can catch parameter issues before runtime.
URL Building Helpers: Create centralized route generation functions that validate parameters:
const routes = {
user: (id: string) => {
if (!id?.trim()) throw new Error('User ID required');
return `/users/${id}`;
},
product: (id: string, tab?: string) => {
if (!id?.trim()) throw new Error('Product ID required');
return tab ? `/products/${id}/${tab}` : `/products/${id}`;
}
};
// Usage ensures validation
navigate(routes.user(userId));Testing: When testing components with dynamic routes, ensure your mock data includes valid IDs. Empty or missing IDs in test fixtures are a common source of this error in test environments.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite