Problem/Motivation
Three of the validation constraints for link fields give the error message "The path '@uri' is invalid." The following screenshot demonstrates this error message when displayed via the inline_form_errors module:

The three constraint classes are:
LinkExternalProtocolsConstraintLinkNotExistingInternalConstraintValidatorcatches 3 different kinds of exception which all produce this message.LinkTypeConstraintValidatorhandles two different errors (link is internal but only externals allowed and vice versa) but only shows this message for both.
This makes it difficult to figure out what is wrong with a field value.
Per the usability review in #48, is preferred to use the name of the subfield "URL" instead of "path" in error messages and when referring to external URLs.
Steps to reproduce
Proposed resolution
Explain the specific problem in the validation messages, so the user knows what they need to fix.
| Class | Sample input | New message |
|---|---|---|
LinkAccessConstraint |
Any path forbidden to the current user | The URL '@uri' is inaccessible. |
LinkExternalProtocolsConstraint |
invalid://not-a-valid-protocol | The URL '@uri' has an invalid protocol. |
LinkNotExistingInternalConstraint |
entity:non_existing_entity_type/yar | The URL '@uri' doesn't exist. |
LinkNotExistingInternalConstraint |
entity:user/invalid-parameter | The URL '@uri' has an invalid parameter. |
LinkNotExistingInternalConstraint |
Unknown | The URL '@uri' is missing a required parameter. |
LinkTypeConstraint |
http:// | The URL '@uri' is invalid. |
LinkTypeConstraint |
(In an external-only field) /node/add | The URL '@uri' is external, but the @field-label field only supports internal paths. |
LinkTypeConstraint |
(In an internal-only field) http://www.example.com/ | The URL '@uri' is internal, but the @field-label field only supports external URLs. |
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #51 | before.png | 29.78 KB | dcam |
| #4 | Issue_in_tests.png | 159.1 KB | andregp |
Issue fork drupal-3262935
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
Comment #2
andregp commentedI'll work on a patch to improve these messages. :)
Comment #3
joachim commentedGreat! I've added a bit more detail -- in some cases, the messages need to be split.
Comment #4
andregp commentedThis patch adds new messages for each exception case. I tried adding some tests too to check for these messages, but I wasn't able to do it (I still lack some knowledge).
Also, it seems that I have found another issue on the LinkNotExistingInternalConstraintValidatorTest.php.
When I check the non-existent url against the MissingMandatoryParametersException (or even InvalidParameterException) the test still passes with no fails. Apparently the current tests don't check correctly for the Exception type.
Comment #5
andregp commentedSorry, I sent the wrong patch. Here is the right one.
Edit: It will fail because of tests/src/Functional/LinkFieldTest.php. It needs to be updated to handle the new added messages.
Edit 2: Here is a partial example of an update for LinkFieldTest::testURLValidation. It is far from ideal though. It doesn't check for paths without required parameters, and also don't verify about the internal/external link requirement (see LinkTypeConstraintValidator).
Comment #6
larowlanFeels like a task more than a bug
Comment #7
joachim commented> Feels like a task more than a bug
I'd say it's a bug because the user doesn't get enough information to fix the problem with their data.
I was working on migrations when I found this and to understand what was causing my data to get this validation error I had to put dump() statements in all the validation plugins to see which one was actually firing.
Comment #8
joachim commentedThis isn't the right approach.
The way Symfony validator plugins work is that the Constraint class defines messages as properties, and the Validator class uses them. (I have no idea why, I find it weird.)
So we need the matching constraint class to define multiple messages, which is fine (see EntityUntranslatableFieldsConstraint for an example).
Comment #9
andregp commentedThanks @joachin for the orientation!
Here is a new patch according to comment #8. I'm not sure how to update the tests though, so still needs work.
Comment #10
joachim commentedThis is looking good!
For the tests you'll need to look at each failing test, and change the violation message that the test is checking.
This can just be removed.
Rename this to invalidMessage.
Instead of a switch, I would put the setting of the message near the problem.
The catch() is for invalid URLs.
The wrong type errors only happen if the URL is valid.
Comment #11
andregp commentedThanks @joachin for pointing these out! I'm gonna work on it.
Regarding the tests, I'm able to make it pass, but I don't know how to cover some cases like: missing parameter (see #5), path should be external, and path should be internal.
As far as I could see these are not covered by the actual tests.
Comment #12
andregp commentedHere is the new patch with partially done tests. Even if it pass the bot I still believe it need more test coverage because some of the new error messages introduced here are not tested (see #11).
#10.1 Done
#10.2 Done
#10.3 Fixed
Comment #13
andregp commentedSorry, forgot to attach the patch.
Comment #15
Tauany Bueno commentedhi,
i'll work on it :)
Comment #16
Tauany Bueno commentedHi!
I applied the patches and re-rolled to 9.5.x.
Everything seems to be correct and apparently the only thing that is missing are the tests as mentioned in comment #11. I'm not really sure how I should implement those tests, so if someone can give me some references and guidence, I can try to work on it :)
Comment #17
sophiavs commentedHi, i'll be trying to do those changes on the tests
Comment #18
sophiavs commentedI tried to make the tests but i couldn't do the "The path '@link_path' is missing a required parameter.", but the tests on internal and external uri was implemented.
Comment #19
gquisini commentedI'll be working on this one.
Comment #20
gquisini commentedAfter spending some time and asking for help trying to find a possible way to test it, I'm changing to RTBC. I'm doing this because it is not possible to manually add a path with an empty mandatory parameter. I tried different combination but could not test it manually.
Comment #21
alexpottI think inspired by the refactoring above to remove $allowed we should do the same here to $uri_is_valid. And we can remove other unnecessary logic here too - any performance improvement by checking LINK_GENERIC is likely to be immeasureable.
Comment #22
mohit_aghera commentedFixing the feedback mentioned in #21
All the functional tests are still passing on local.
Comment #24
smustgrave commentedRunning tests against 10.1
Comment #25
smustgrave commentedConfirm the feed back from #21 has been addressed
Passed the 10.1 tests too.
Code looks good to me so +1 for RTBC
Comment #26
quietone commentedSorry folks, there is commented out code.
Adding commented out code is not a good idea. What is the purpose? This almost reads like a reminder to add a test. Is it? By the way, there is an issue to find and resolve all instances #2909362: [meta] Commented-out code in Drupal.
Comment #27
harshitthakoreThe line of code is additional and not in use. So I've removed it. please review the patch.
Comment #28
harshitthakoreComment #29
smustgrave commentedTagging for usability for the new sayings.
If someone could please update the issue summary with what was being updated
This is a little vague.
Comment #30
joachim commentedExpanded the IS.
Comment #31
smustgrave commentedChanges look good.
+1 from me after the usability review
Comment #32
murilohp commentedThis is just suggestion, but since we're already refactoring this code, I thought we could change this
issetstatement to be$value instanceof LinkItemInterface, this way we're already validating if it's isset or not and we could remove both lines 21 and 22 because using instanceof, the LSP will be able to understand the variable type. Something like:This suggestion also uses an early return, just to improve the code complexity. What do you think?
Besides that, the code looks good and since my suggestion is just a nitpick, I'll leave this issue as NR.
Comment #33
larowlanWe can add string property type hints here now.
Here too
#32 seems reasonable to me
This looks very close to me
Comment #34
murilohp commentedHey @larowlan, here's a patch with your suggestions and #32, now I think it's good.
PS: The interdiff has a change on the LinkFieldTest file, this is a reroll since this file had changed recently on #3300957: Potentially speed up LinkFieldTest
Comment #35
joachim commented> This is just suggestion, but since we're already refactoring this code, I thought we could change this isset statement to be $value instanceof LinkItemInterface
I don't actually think this is a good idea.
Reading this code:
makes me think, 'Under what circumstances is the $value NOT a LinkItemInterface? When might be be something else? What would it mean in that case?'
It makes the code confusing and adds to cognitive load.
Comment #36
murilohp commentedHey @joachim, I think I was too much in a hurry yesterday with my suggestion(sorry :( ), when I saw:
I just thought about making this piece of code better, I thought "ok, the $value will always be mixed and we're creating another variable just to type hint the interface, so why not validate the $value instance, this way we could remove the unnecessary $link_item variable and also type hint the $value itself", so I haven't thought about some stuff like "Under what circumstances is the $value NOT a LinkItemInterface?", just thought it would be a good idea to validate the instance type because IMHO is a good practice to validate the instance before using it(when we cannot change the method signature).
Comment #38
lauriiiThe new validation messages at least make sense to me. I agree that it's a good idea to pay extra attention to the error messages because they are critical to user experience.
Comment #39
smustgrave commentedThanks @lauriii!
Retesting #34
Having a link field just for internal and using link "https://www.google.com/ generates The path 'https://www.google.com/' is external, but the link field only supports internal paths."
Having a link field just for external and using /node/1 I actually don't get an error but an HTML popup "Please enter URL" which isn't super clear
Inputting /node/2333 (node that doesn't exist) also does not trigger an error.
Can these be confirmed this is a desired behavior?
Comment #40
s_leu commentedThe code seems to some extent expect that it is not a LinkItemInterface because
will return true even if LinkItem->isEmpty() returns TRUE. I think there's definitely room for improvement there, which is of course not necessarily part of this issue, and
could break certain scenarios, so this isn't right I think. I filed a separate issue addressing this: #3387013: Check LinkItemInterface::isEmpty() before validating
Comment #43
benjifisherUsability review
We discussed this issue at #3449637: Drupal Usability Meeting 2024-05-31. That issue will have a link to a recording of the meeting.
For the record, the attendees at the usability meeting were @benjifisher, @rkoller, @simohell, @shaal, and @SKAUGHT.
If you want more feedback from the usability team, a good way to reach out is in the #ux channel in Slack.
We agree that having more specific error messages is an improvement, and I am adding the Usability tag. The suggested messages are clear. We think it might help to come up with a shorter version of these two:
We do not have a firm recommendation, but it might help to break each one into two, short sentences. For example, the second might be "The path '@uri' is internal. This field only supports external paths." Can we use the field label instead of "This field"?
I am also adding the tag for an issue summary update:
.
I also created a merge request based on the patch in #34. I edited some context lines in the patch so that it applies to the current 11.x branch.
Comment #44
benjifisherComment #45
joachim commented> Can we use the field label instead of "This field"?
Done, and rebased.
> We do not have a firm recommendation, but it might help to break each one into two, short sentences. For example, the second might be "The path '@uri' is internal. This field only supports external paths."
I understand the desire to have shorter, simpler sentences but removing the 'but' between these two clauses removes meaning. Without it, it's less clear what the connection is between these two statements. It's like saying 'My cat eats cat food. This field only supports external paths' -- the reaction is -- 'so??'
Still needs IS update and screenshots. Tagging as Novice for those two tasks.
Comment #46
dcam commentedPostponing on #3387013: Check LinkItemInterface::isEmpty() before validating which makes the same change to check field values are LinkItemInterfaces.
Comment #47
dcam commentedThis is unblocked.
Comment #48
benjifisherUsability Review
The usability team had another look at this issue at the #3566641: Drupal Usability Meeting 2026-01-16. The participants were @benjifisher, @pallavi singh3013, @rkoller, and @simohell. I am giving them contribution credit on this issue.
In the previous usability review (Comment #43), I asked for screenshots of each possible error message. I have changed my mind. One set of before/after screenshots would be nice, and the new messages should be listed in the Proposed resolution section, but we do not need more screenshots than that.
In Comment #43, I added the tag for an issue summary update. This issue still needs that update.
In this round of review, we added a Link field with the default settings. In particular, it allows both internal and external links. We noticed two problems.
Error messages should not assume links are internal.
When we entered "www.drupal.org" for the URL, using the feature branch for this issue, we got the error message,
It is possible that the site has a page
/www.drupal.org, so adding the leading/is the correct fix. But it is also possible that the user intended to give an external URL and forgot the protocolhttps://. (It is also possible that the user intended a query parameter or fragment, so a leading?or#is the correct fix.) The error message in the 11.x branch is more complete:Ideally, the message would depend on the configuration of the field:
The term "path" should not be used to refer to external links.
With the default settings, the Link field has two parts (subfields), labeled "URL" and "Link text". If the error message refers to "path", then it is not clear that the user should change the URL value. Also, if the user wants to enter an external link, then "path" is not the correct term to use.
We do not have a firm recommendation, but some possibilities are to refer to "internal link" and "external link" or to "path" and "URL", depending on the type of link. It might also make sense to change the label of the first part to "path", "URL", or "URL or path", depending on how the field is configured. (That might not be in scope for this issue.)
Comment #50
mradcliffeI performed Novice Triage on this issue. I am leaving the Novice tag on this issue because I think that we can use technical writing and reading comprehension skills to update the issue summary from #48 usability team review, and then remove the Needs issue summary update tag. Then if we feel comfortable after understanding the issue, go ahead and rebase or make the changes based on that review.
The Drupal Contribution Mentoring team is triaging issues for DrupalCon Chicago 2026, and we are reserving this issue for Mentored Contribution during the event.
After Thursday 26th March 2026 + 1 DAY (13:00 UTC), this issue returns to being open to all. Thanks!
Comment #51
dcam commentedComment #52
dcam commentedRE: #48
This was the focus of #2828556: Display meaningful error messages according to the link type, which was committed about a week before comment #48 was made. It was responsible for updating the error messages mentioned as being on the 11.x branch. Those error messages already change based on the internal/external settings.
I updated the MR to change the constraint classes to refer to the URL subfield instead of "path" and when referring to external URLs.
A pre-MR screenshot was added to the issue summary. I added a table that shows sample input to trigger the validation messages, along with the updated messages.
Comment #53
dcam commentedThat last test run crashed.
Comment #54
smustgrave commentedTested with all the same inputs provided and do get the new messages (not going to spam the screenshots) but will say this also seems to address a random php warning
Message Warning: Undefined array key 1 in Drupal\link\Plugin\Field\FieldWidget\LinkWidget::getUriAsDisplayableString() (line 75 of /var/www/html/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php)I got when trying entity:non_existing_entity_type/yarI did start a new pipleline and it's all green.
Think this is good to go.
Comment #55
godotislateThis will need a separate MR for 11.x to do a deprecation of a constraint option/parameter. (It likely would've needed a separate 11.x MR anyway.)