Problem/Motivation

In our project, we wanted to stop having path aliases suffixed by "-INCREMENT" for existing ones, instead show to the contributor that the path alias already exists.
With this update, the content save action is still done, but no path alias is generated and an error message is displayed.

Steps to reproduce

  1. Tick the new settings Bypass alias uniquifier
  2. Create a new node with an existing path alias and save

Proposed resolution

Create a new setting which allows to bypass the path alias uniquifier for existing aliases.

Remaining tasks

Add tests.

User interface changes

API changes

Data model changes

Issue fork pathauto-3275041

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Heisen-blue created an issue. See original summary.

Heisen-blue’s picture

Issue summary: View changes
StatusFileSize
new2.3 KB
Heisen-blue’s picture

Status: Active » Needs review
berdir’s picture

Not sure about this. Throwing an exception seems strange. If you want to prevent this, why not make it a form validation?

mdranove’s picture

Not sure about this. Throwing an exception seems strange. If you want to prevent this, why not make it a form validation?

Form validation checks against the value in the alias field. Pathauto alias generation takes place later in the node save process, after hook_presave.

Here's an issue I've run into in my project which I think this patch could help solve:

  • You have a pathauto pattern configured to create alias based on a node's title.
  • Content manager creates a node with the following title: 'Example Title 1'. This resolves to the following alias: '/example-title-1'.
  • 2 years later, another content manager creates a node with same title: 'Example Title 1'. This resolves to the following alias '/example-title-1-0'.
  • Nobody notices the -0 in the alias until the link is shared far and wide.

I do think that pathauto module is what needs to either hooked into by individual developers, or patched like is suggested here in order to resolve this. I've tried hooking into the form_state as well as hook_entity_presave and am only given the value of the 'alias' field, which, as I describe above, is not really the issue, the issue is the duplicate alias which pathauto generates later in the entity save process.

mdranove’s picture

Created a module which uses a custom form validator to check to make sure that users wont generate a duplicate url alias on form save. Form validator builds entity object and sends it over to an extension of PathautoGenerator to perform the check. Issues error message on dupe instead of throwing exception.

https://www.drupal.org/project/unique_alias_checker

vamirbekyan’s picture

unfortunately unique_alias_checker module does not work with node:origin:title token.

shabana.navas’s picture

+++ b/src/PathautoGenerator.php
@@ -247,6 +247,12 @@ class PathautoGenerator implements PathautoGeneratorInterface {
+      throw new \InvalidArgumentException('Path alias should be unique.');

I think we can change this error message to be a bit more informative. Something like:

        throw new \InvalidArgumentException(sprintf('The automatically generated alias %s for path %s conflicted with an existing alias.',
          $alias,
          $internalPath,
        ));

would help admins figure out which are the problematic aliases.

shabana.navas’s picture

shabana.navas’s picture

StatusFileSize
new2.41 KB

Earlier patch didn't apply. Adding again with informative error message.

berdir’s picture

Status: Needs review » Needs work

I'm not convinced that this feature is important enough to be added to the main module. the uniquifier is a service, the module that was created could implement this approach by wrapping the service and implementing this logic there.

To be added, tests would be required and a merge requests, patches are no longer tested.

mably made their first commit to this issue’s fork.

mably’s picture

Status: Needs work » Needs review

That's a pretty light-weight feature that could be useful to some people.
Can be manually tested using the Tugboat instance associated to this issue's MR.

Problem

When multiple entities generate the same URL alias pattern, Pathauto appends a numeric suffix (e.g. /content/test-0, /content/test-1) to make each alias unique. In some cases, site administrators prefer to skip alias generation entirely rather than create suffixed duplicates.

Feature

A new Disable alias uniquifier checkbox is added to the Pathauto settings form. When enabled, if the generated alias already exists, Pathauto skips alias creation for that entity instead of appending a suffix. A warning message is displayed to inform the user that the alias was skipped.

Changes

  • New disable_uniquify boolean config setting (default: FALSE)
  • Config schema updated
  • Checkbox added to the settings form
  • In PathautoGenerator::createEntityAlias(), when the setting is enabled and the alias is reserved, a warning is shown via the core messenger and alias creation is skipped

Test coverage

A kernel test (testDisableUniquify) verifies:

  1. Default behavior still works (alias gets a -0 suffix)
  2. With the setting enabled, no alias is created for conflicting paths
  3. A warning message is displayed to the user
  4. Entities with unique titles still get aliases normally

mably changed the visibility of the branch 3275041-add-bypass-setting to hidden.

mably’s picture

Mandatory screenshot from Tugboat:

Warning message

berdir’s picture

Per #11, I'm not convinced we need to support this feature. For me it doesn't fit into how pathauto works, in that it's automatic and editors shouldn't have to worry about. I don't see how no alias is better than a -0, especially after if you're only informed of this after the fact. It's not clear what editors should do then, if this is a common occurance then possibly a different pattern should be used that includes more information such as a date for articles.

mably’s picture

Claude helped me generate an argumentation, just in case 😉

Why "no alias" can be better than "-0"

The "-0" suffix is the worst of both worlds: it looks intentional, so it goes unnoticed — but it isn't intentional, so it causes real harm. An editor who sees /node/123 in the browser bar knows immediately something is off and will take action. An editor who sees /example-title-1-0 assumes it's correct and shares it on social media, prints it on flyers, sends it in newsletters. Two years later somebody notices the ugly -0, and by then the URL is baked into backlinks and external references. This is the exact real-world scenario described in #5.

In other words: a missing alias is an obvious, immediately fixable problem. A silently suffixed alias is a hidden, long-lived problem.

The warning IS the editor workflow

The concern about "what should editors do next" is exactly what the warning message solves. When disable_uniquify is enabled and a conflict occurs, the editor sees immediately on save: "Alias /example-title already exists. Skipped." — they can then edit the node and set a distinct manual alias, adjust the title, or coordinate with the other content owner. This is proactive notification at the right moment, versus the current silent suffixing that nobody catches until it's too late.

"Use a different pattern" isn't always an option

Adding dates or content types to URL patterns (/2026/02/example-title) works for some sites, but many SEO strategies and editorial guidelines require clean, short, title-only URLs. The issue isn't bad pattern design — it's that content teams need to be aware of conflicts when they happen, so they can make a conscious decision.

Precedent: pathauto already has policy settings for edge cases

Pathauto is automatic, but it already offers three update_action policies (do nothing / create new alias / delete old alias) because different sites need different behaviors in edge cases. disable_uniquify follows the exact same principle: it's a policy decision about what the automatic system should do when faced with a conflict. It defaults to FALSE — zero change for existing sites — and only activates when a site administrator consciously opts in.

The implementation is minimal

The entire logic is 6 lines of code in createEntityAlias(): check the config, call the existing isReserved() method, show a warning, return NULL. Plus a checkbox in the settings form, schema, and update hook. The feature is fully covered by a kernel test. There's no new service, no new plugin, no architectural change — just a lightweight opt-in setting that solves a real pain point reported by multiple people over the last 4 years.

Why not a separate module?

The unique_alias_checker module was created (#6) but it has limitations — it doesn't work with all tokens (#7) and relies on extending PathautoGenerator, which is fragile across updates. The reason it doesn't work well externally is that the right insertion point is inside createEntityAlias(), between alias generation and uniquification — exactly where this patch puts it. A 6-line addition in the right place is more robust than an external module trying to replicate internals.

berdir’s picture

Well, now ask the yes-machine, aka Claude why we should _not_ do this and let it argue with itself. The "precedent" we just talked about yesterday, I also think that possibly shouldn't exist, not like that. And years of real world situations have shown me that no, many editors do not care about missing aliases and aren't going to notice it at all or would know what to do with such a situation. And if it's a case when they want a nice URL, for example to put in on a flyer, they will also notice the -0 and not like that and do something about it.

mably’s picture

Status: Needs review » Closed (won't fix)

Ok, no problem.

The original ticket author seems to have moved on.

So let's close it as Won't fix.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

mably’s picture

Here are its arguments in favor of "closing" 😉

A missing alias is strictly worse than a -0 alias

With -0, the entity has a working, crawlable, human-readable URL that can be shared, indexed by search engines, and used in navigation menus. With no alias, the entity falls back to /node/123 — which is catastrophically worse for SEO, completely defeats the purpose of pathauto, and is far more likely to go unnoticed by editors than a -0 suffix.

The warning comes after the fact

The editor sees "Alias skipped" as a status message after save. Then what? They have to: notice the warning, understand what it means, go back to the edit form, open the URL alias settings, manually type a unique alias. Most editors won't do any of this — they'll move on and the entity stays on /node/123 indefinitely. The -0 suffix at least gives them a working URL immediately, and pathauto already shows a message when uniquification occurs.

It's a global nuclear option

The setting applies to all entity types and bundles. You can't say "disable uniquification for articles but keep it for products." Running "Generate URL aliases" in bulk with this setting enabled could silently strip aliases from dozens of entities in one go, leaving them all on raw system paths.

The real problem calls for a different solution

If -0 suffixes are a recurring problem, it means the URL pattern isn't distinctive enough. The correct fix is to improve the pattern (add a date, taxonomy term, or node ID), not to stop generating aliases altogether. If a site truly needs pre-save validation ("this title already exists, please change it"), that belongs in form validation — a custom module or the existing unique_alias_checker contrib — not in a post-save bail-out.

The uniquifier service is already replaceable

Sites with exotic requirements can override pathauto.alias_uniquifier in their services file and implement any policy they want — skip, throw, log, notify via Slack. This is the Drupal way: swap the service, don't add a checkbox for every edge case. Adding a global on/off toggle to core for something that affects 1% of sites creates maintenance burden for the 99% who never need it.

mably’s picture

So, what would be your final word?

After arguing both sides, I'm siding with berdir. The issue should stay closed.

The -0 suffix is ugly, but it's a working URL. A missing alias means the entity falls back to /node/123 — which is a broken experience that nobody notices until it's too late. Ironically, the "hidden, long-lived problem" argument we used for the feature applies more strongly against it: an editor who wouldn't notice a -0 suffix will also ignore a status message warning, except now they're left with a raw system path instead of a functional human-readable URL.

The service override approach is the right one. Any site that genuinely needs custom conflict behavior can swap pathauto.alias_uniquifier in their services file — that's cleaner and more flexible than a global checkbox that 99% of sites will never touch.