Index: pathauto.inc
===================================================================
--- pathauto.inc	(revision 3023)
+++ pathauto.inc	(working copy)
@@ -57,6 +57,20 @@
 }
 
 /**
+ * Return an array of taken name exceptions.
+ *
+ * Some tokens violate the naming convention enforced by Pathauto and are
+ * treated as paths even though they are not. We need to explictly list them to
+ * be sure to treat them the proper way.
+ *
+ * @return
+ *   An array of token names.
+ */
+function _pathauto_token_exceptions() {
+  variable_get('pathauto_token_exceptions', array('bookpath', 'bookpath-raw', 'menupath', 'menupath-raw'));
+}
+
+/**
  * Clean up a string segment to be used in an URL alias.
  *
  * Performs the following possible alterations:
@@ -560,11 +574,12 @@
  *   An array of the cleaned tokens.
  */
 function pathauto_clean_token_values($full) {
+  $exceptions = _pathauto_token_exceptions();
   $replacements = array();
   foreach ($full->values as $key => $value) {
     // Only clean non-path tokens.
     $token = $full->tokens[$key];
-    if (!preg_match('/(path|alias|url|url-brief)(-raw)?$/', $token)) {
+    if (in_array($token, $exceptions) || !preg_match('/(path|alias|url|url-brief)(-raw)?$/', $token)) {
       $replacements[$token] = pathauto_cleanstring($value);
     }
     else {
