diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts
index bb3f92735b..e9efdea445 100644
--- a/packages/router-generator/src/generator.ts
+++ b/packages/router-generator/src/generator.ts
@@ -43,6 +43,7 @@ import {
 } from './utils'
 import { fillTemplate, getTargetTemplate } from './template'
 import { transform } from './transform/transform'
+import { validateRouteParams } from './validate-route-params'
 import type { GeneratorPlugin } from './plugin/types'
 import type { TargetTemplate } from './template'
 import type {
@@ -1056,6 +1057,10 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved
       throw new Error(`⚠️ File ${node.fullPath} does not exist`)
     }
 
+    if (node.routePath) {
+      validateRouteParams(node.routePath, node.filePath, this.logger)
+    }
+
     const updatedCacheEntry: RouteNodeCacheEntry = {
       fileContent: existingRouteFile.fileContent,
       mtimeMs: existingRouteFile.stat.mtimeMs,
diff --git a/packages/router-generator/src/validate-route-params.ts b/packages/router-generator/src/validate-route-params.ts
new file mode 100644
index 0000000000..62c7a8403c
--- /dev/null
+++ b/packages/router-generator/src/validate-route-params.ts
@@ -0,0 +1,118 @@
+import type { Logger } from './logger'
+
+/**
+ * Regex for valid JavaScript identifier (param name)
+ * Must start with letter, underscore, or dollar sign
+ * Can contain letters, numbers, underscores, or dollar signs
+ */
+const VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/
+
+interface ExtractedParam {
+  /** The param name without $ prefix (e.g., "userId", "optional") */
+  paramName: string
+  /** Whether this param name is valid */
+  isValid: boolean
+}
+
+/**
+ * Extracts param names from a route path segment.
+ *
+ * Handles these patterns:
+ * - $paramName                     -> extract "paramName"
+ * - {$paramName}                   -> extract "paramName"
+ * - prefix{$paramName}suffix       -> extract "paramName"
+ * - {-$paramName}                  -> extract "paramName" (optional)
+ * - prefix{-$paramName}suffix      -> extract "paramName" (optional)
+ * - $ or {$}                       -> wildcard, skip validation
+ */
+function extractParamsFromSegment(segment: string): Array<ExtractedParam> {
+  const params: Array<ExtractedParam> = []
+
+  // Skip empty segments
+  if (!segment || !segment.includes('$')) {
+    return params
+  }
+
+  // Check for wildcard ($ alone or {$})
+  if (segment === '$' || segment === '{$}') {
+    return params // Wildcard, no param name to validate
+  }
+
+  // Pattern 1: Simple $paramName (entire segment starts with $)
+  if (segment.startsWith('$') && !segment.includes('{')) {
+    const paramName = segment.slice(1)
+    if (paramName) {
+      params.push({
+        paramName,
+        isValid: VALID_PARAM_NAME_REGEX.test(paramName),
+      })
+    }
+    return params
+  }
+
+  // Pattern 2: Braces pattern {$paramName} or {-$paramName} with optional prefix/suffix
+  // Match patterns like: prefix{$param}suffix, {$param}, {-$param}
+  const bracePattern = /\{(-?\$)([^}]*)\}/g
+  let match
+
+  while ((match = bracePattern.exec(segment)) !== null) {
+    const paramName = match[2] // The param name after $ or -$
+
+    if (!paramName) {
+      // This is a wildcard {$} or {-$}, skip
+      continue
+    }
+
+    params.push({
+      paramName,
+      isValid: VALID_PARAM_NAME_REGEX.test(paramName),
+    })
+  }
+
+  return params
+}
+
+/**
+ * Extracts all params from a route path.
+ *
+ * @param path - The route path (e.g., "/users/$userId/posts/$postId")
+ * @returns Array of extracted params with validation info
+ */
+function extractParamsFromPath(path: string): Array<ExtractedParam> {
+  if (!path || !path.includes('$')) {
+    return []
+  }
+
+  const segments = path.split('/')
+  const allParams: Array<ExtractedParam> = []
+
+  for (const segment of segments) {
+    const params = extractParamsFromSegment(segment)
+    allParams.push(...params)
+  }
+
+  return allParams
+}
+
+/**
+ * Validates route params and logs warnings for invalid param names.
+ *
+ * @param routePath - The route path to validate
+ * @param filePath - The file path for error messages
+ * @param logger - Logger instance for warnings
+ */
+export function validateRouteParams(
+  routePath: string,
+  filePath: string,
+  logger: Logger,
+): void {
+  const params = extractParamsFromPath(routePath)
+  const invalidParams = params.filter((p) => !p.isValid)
+
+  for (const param of invalidParams) {
+    logger.warn(
+      `WARNING: Invalid param name "${param.paramName}" in route "${routePath}" (file: ${filePath}). ` +
+        `Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/).`,
+    )
+  }
+}
diff --git a/packages/router-generator/tests/generator/invalid-param-names/routeTree.snapshot.ts b/packages/router-generator/tests/generator/invalid-param-names/routeTree.snapshot.ts
new file mode 100644
index 0000000000..4728dd439e
--- /dev/null
+++ b/packages/router-generator/tests/generator/invalid-param-names/routeTree.snapshot.ts
@@ -0,0 +1,95 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as ValidParamRouteImport } from './routes/$validParam'
+import { Route as UserNameRouteImport } from './routes/$user-name'
+import { Route as R123RouteImport } from './routes/$123'
+
+const ValidParamRoute = ValidParamRouteImport.update({
+  id: '/$validParam',
+  path: '/$validParam',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const UserNameRoute = UserNameRouteImport.update({
+  id: '/$user-name',
+  path: '/$user-name',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const R123Route = R123RouteImport.update({
+  id: '/$123',
+  path: '/$123',
+  getParentRoute: () => rootRouteImport,
+} as any)
+
+export interface FileRoutesByFullPath {
+  '/$123': typeof R123Route
+  '/$user-name': typeof UserNameRoute
+  '/$validParam': typeof ValidParamRoute
+}
+export interface FileRoutesByTo {
+  '/$123': typeof R123Route
+  '/$user-name': typeof UserNameRoute
+  '/$validParam': typeof ValidParamRoute
+}
+export interface FileRoutesById {
+  __root__: typeof rootRouteImport
+  '/$123': typeof R123Route
+  '/$user-name': typeof UserNameRoute
+  '/$validParam': typeof ValidParamRoute
+}
+export interface FileRouteTypes {
+  fileRoutesByFullPath: FileRoutesByFullPath
+  fullPaths: '/$123' | '/$user-name' | '/$validParam'
+  fileRoutesByTo: FileRoutesByTo
+  to: '/$123' | '/$user-name' | '/$validParam'
+  id: '__root__' | '/$123' | '/$user-name' | '/$validParam'
+  fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+  R123Route: typeof R123Route
+  UserNameRoute: typeof UserNameRoute
+  ValidParamRoute: typeof ValidParamRoute
+}
+
+declare module '@tanstack/react-router' {
+  interface FileRoutesByPath {
+    '/$validParam': {
+      id: '/$validParam'
+      path: '/$validParam'
+      fullPath: '/$validParam'
+      preLoaderRoute: typeof ValidParamRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/$user-name': {
+      id: '/$user-name'
+      path: '/$user-name'
+      fullPath: '/$user-name'
+      preLoaderRoute: typeof UserNameRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/$123': {
+      id: '/$123'
+      path: '/$123'
+      fullPath: '/$123'
+      preLoaderRoute: typeof R123RouteImport
+      parentRoute: typeof rootRouteImport
+    }
+  }
+}
+
+const rootRouteChildren: RootRouteChildren = {
+  R123Route: R123Route,
+  UserNameRoute: UserNameRoute,
+  ValidParamRoute: ValidParamRoute,
+}
+export const routeTree = rootRouteImport
+  ._addFileChildren(rootRouteChildren)
+  ._addFileTypes<FileRouteTypes>()
diff --git a/packages/router-generator/tests/generator/invalid-param-names/routes/$123.tsx b/packages/router-generator/tests/generator/invalid-param-names/routes/$123.tsx
new file mode 100644
index 0000000000..5ead8abbb3
--- /dev/null
+++ b/packages/router-generator/tests/generator/invalid-param-names/routes/$123.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/$123')({
+  component: () => <div>Invalid param starting with number</div>,
+})
diff --git a/packages/router-generator/tests/generator/invalid-param-names/routes/$user-name.tsx b/packages/router-generator/tests/generator/invalid-param-names/routes/$user-name.tsx
new file mode 100644
index 0000000000..4913327d6c
--- /dev/null
+++ b/packages/router-generator/tests/generator/invalid-param-names/routes/$user-name.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/$user-name')({
+  component: () => <div>Invalid param with hyphen</div>,
+})
diff --git a/packages/router-generator/tests/generator/invalid-param-names/routes/$validParam.tsx b/packages/router-generator/tests/generator/invalid-param-names/routes/$validParam.tsx
new file mode 100644
index 0000000000..6a879114ab
--- /dev/null
+++ b/packages/router-generator/tests/generator/invalid-param-names/routes/$validParam.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/$validParam')({
+  component: () => <div>Valid param</div>,
+})
diff --git a/packages/router-generator/tests/generator/invalid-param-names/routes/__root.tsx b/packages/router-generator/tests/generator/invalid-param-names/routes/__root.tsx
new file mode 100644
index 0000000000..f463b796b4
--- /dev/null
+++ b/packages/router-generator/tests/generator/invalid-param-names/routes/__root.tsx
@@ -0,0 +1,5 @@
+import { createRootRoute, Outlet } from '@tanstack/react-router'
+
+export const Route = createRootRoute({
+  component: () => <Outlet />,
+})
diff --git a/packages/router-generator/tests/validate-route-params.test.ts b/packages/router-generator/tests/validate-route-params.test.ts
new file mode 100644
index 0000000000..14b61adc3d
--- /dev/null
+++ b/packages/router-generator/tests/validate-route-params.test.ts
@@ -0,0 +1,36 @@
+import { join } from 'node:path'
+import { afterAll, describe, expect, it, vi } from 'vitest'
+import { Generator, getConfig } from '../src'
+
+describe('validateRouteParams via generator', () => {
+  const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
+  afterAll(() => {
+    warnSpy.mockRestore()
+  })
+
+  it('should warn for invalid param names when running the generator', async () => {
+    const folderName = 'invalid-param-names'
+    const dir = join(process.cwd(), 'tests', 'generator', folderName)
+
+    const config = getConfig({
+      disableLogging: false, // Enable logging to capture warnings
+      routesDirectory: dir + '/routes',
+      generatedRouteTree: dir + '/routeTree.gen.ts',
+    })
+
+    const generator = new Generator({ config, root: dir })
+    await generator.run()
+
+    // Should have warned about invalid params: $123 and $user-name
+    expect(warnSpy).toHaveBeenCalledWith(
+      expect.stringContaining('Invalid param name'),
+    )
+    expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('123'))
+    expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('user-name'))
+
+    // Should NOT have warned about $validParam
+    expect(warnSpy).not.toHaveBeenCalledWith(
+      expect.stringContaining('validParam'),
+    )
+  })
+})
