Problem/Motivation

Whenever a value is present in the URL alias field while saving a node or its translation, ValidPathConstraintValidator calls $this->pathValidator->isValid($path). If the site uses any contrib or custom modules that implement hook_node_grants() then the access() method in NodeGrantDatabaseStorage queries the node_access table to check the access to determine if the path is valid or not. In the current logic, core uses the language code of the translation being saved in the db query. Now consider the following scenario

  • Node has English as default language and is published.
  • User tries to create a new translation.

In both cases, the node_access table is queried with the language code of the translation being saved to check the access. However, there won’t be any record for the unpublished translation, causing the validation to fail and resulting in the validation error “Either the path '%link_path' is invalid or you do not have access to it”.

Check comments #122 to #125 for more detailed analysis.

Steps to reproduce

  • Install with demo_umami profile
  • Give "Editorial workflow: Use Create New Draft transition" and "Article: Create new content" permissions to the editor role.
  • Check the node_access table. There will be only one entry with nid 0 which is the default record.
  • Create a custom module and implement hook_node_grants(). Install the module.
/**
 * Implements hook_node_grants().
 */
function my_module_node_grants(AccountInterface $account, $operation) {
  $grants = [];

  return $grants;
}
  • Login as admin and visit any admin page. There will be a message to rebuild the permissions. Click on Rebuild permissions to rebuild all permissions.

https://www.drupal.org/files/issues/2024-01-17/3101344-rebuild%20permissions.png

  • Login with any of the editor accounts (Eg: uid=3) in incognito mode.
  • Add an English article. Give a path in URL alias field and publish it.

https://www.drupal.org/files/issues/2024-01-17/3101344-create-article.png

  • Try to add spanish translation.

https://www.drupal.org/files/issues/2024-01-17/3101344-translation-error.png

Proposed resolution

There have been 3 suggested solutions based on where the problem is.

  1. The problem is the node_access table. Option 1 is to modify the database by adding a "nid=0" record in node_access, #15.: But Node access table gets updated everytime permissions are rebuilt. So, not a robust solution.
  2. The problem is the alias field that is being defaulted to the original alias when creating a new translation. Leave that empty, #20 Reported to worķ. #21, #23, #24, #26, #27, #28, #46 and Reported to not work; #44, #45
  3. The problem is that Drupal\path\Plugin\Field\FieldWidget\PathWidget::validateFormElement() sets the form error even if the field is not accessible by user while it should not. #79. Reported to work #83, #85. But will not work if the alias field is visiblie in node edit form
  4. Use fallback language in node_access query when the translation is new: #64, #122 to #125: Needs review

Note that In #30, the problem was not reproducible with core only. The suggestion is that access control modules are causing the problem. See #30, #31

Remaining tasks

Create a merge request - Done
Add tests - Done
Review MR 6210
Commit

User interface changes

API changes

Data model changes

N/A

Release notes snippet

Issue fork drupal-3101344

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

rgpublic created an issue. See original summary.

kbriand’s picture

Same issue here. I found a workaround adding the permission 'link to any page'. But as it is said 'This allows to bypass access checking when linking to internal paths.'. Not sure this is the best solution.

rgpublic’s picture

Ah, at least some other poor soul. I thought I was seeing things or maybe had sth. wrongly configured. This error is so extreme, because you suddenly cannot create any translated content that I wonder how this got through automated testing. Perhaps it's the "unusual" combination of translation, permissions, etc. why this made it through the checks. I also don't know whether I filed this under the right component (path.module). Perhaps some other component like content translation is at fault here, but I had to choose sth. and I just don't know.

rgpublic’s picture

BTW... My current workaround is:

function hook_validation_constraint_alter(array &$definitions) {
    $definitions['ValidPath']=$definitions['NotNull'];
}

Of course also quite disconcerting & radical ... *Shrug*

branislav radovanovic’s picture

Same issue here, workaround is as kbriand mentioned is by turning on permission 'link to any page' or 'bypass access control'.
None of them are good solutions but 'link to any page' is a lesser evil. This should be fixed as soon as possible.

dtv_rb’s picture

Same problem with users who have the permissions to create and edit their own (published/unpublished) nodes but not the "view own unpublished content" permission. This is caused by the "ValidPath" constraint which is added directly to the path base field of the entity.

It should definitly be mentioned somewhere, it cost me a few hours to reverse engineer this.

When the user has the permission to edit a node, submitting the edit form should not produce an error!

I think a "validPath" constraint without permission check would solve this.

drupalpune12’s picture

Priority: Normal » Major

+1 for facing this issue.

This is definitely a major issue if not critical. Bumping.

gbaldwin’s picture

+1 Same issue. After 8.8 update, users other than god admin get this error when creating new translations.
We do have pathauto installed.
God admin can create translations but every other user role with permissions to add translation receive the same error.

kplatis’s picture

+1 for the issue after upgrading to 8.8 . Temporarily solved when adding the permission 'link to any page' but apparently it is not a good solution.

gbaldwin’s picture

Udpate: 'link to any page' permissions did solve this problem, but the side effect was that all menu links were available to all user roles whether or not they had permission to view the pages. So unfortunately that permission didn't work for us, but the hook in #4 does.

skaught’s picture

possible related #3107252: Missing plugin notice after every merge and cache clear, cache_discovery table

also see:
https://drupal.stackexchange.com/questions/254453/cache-rebuild-causes-a...

if you have command line and drush:

drush cr
drush sql-query 'TRUNCATE TABLE cache_discovery;'

OR if you have devel_php module installed: on /devel/php run command

  drupal_flush_all_caches();
\Drupal::database()->truncate('cache_discovery')->execute();
skaught’s picture

after some thought. my linked issue probably isn't related. but will leave in case.. My project is also multilingual but I am not having any validate error.

---
toward this original issue: have you been able to run Drupals Update process (/update.php) if you have access to trigger it or thru Admin toolbar link?

mschudders’s picture

In "PathWidget"

    // Trim the submitted value of whitespace and slashes.
    $alias = rtrim(trim($element['alias']['#value']), " \\/");
    if (!empty($alias)) {
      $form_state->setValueForElement($element['alias'], $alias);

      /** @var \Drupal\path_alias\PathAliasInterface $path_alias */
      $path_alias = \Drupal::entityTypeManager()->getStorage('path_alias')->create([
        'path' => $element['source']['#value'],
        'alias' => $alias,
        'langcode' => $element['langcode']['#value'],
      ]);
      $violations = $path_alias->validate();

      foreach ($violations as $violation) {
        // Newly created entities do not have a system path yet, so we need to
        // disregard some violations.
        if (!$path_alias->getPath() && $violation->getPropertyPath() === 'path') {
          continue;
        }
        $form_state->setError($element['alias'], $violation->getMessage());
      }
    }

When creating a new Node => $alias is empty.

When translating a Node => $alias is the alias of the source language. This doesn't seem to be right.

Also there seems to be some sort of check:

// Newly created entities do not have a system path yet, so we need to
        // disregard some violations.

But this expression ins't TRUE.
It has a path "node/X" and the propertypath = path.0.value

When "formElement" gets called in PathWidget
it get passed $items, and this contains the source Language PATH Alias but with a langcode of the new language.... Pretty weird

When getting deeper in the code.
We receive an AccessResultNeutral by hook_node_access (doesn't check 'view' permission) & by NodeGrantDatabaseStorage.php because he doesn't find any result in the DB.
This results an thrown error in AccessAwareRouter.php:

if (<strong>!$access_result->isAllowed()</strong>) {
  if ($access_result instanceof CacheableDependencyInterface && $request->isMethodCacheable()) {
    t<strong>hrow new CacheableAccessDeniedHttpException($access_result, $access_result instanceof AccessResultReasonInterface ? $access_result->getReason() : NULL);</strong>
  }
  else {
    throw new AccessDeniedHttpException($access_result instanceof AccessResultReasonInterface ? $access_result->getReason() : NULL);
  }
}

thus resulting in the violation ....

Stack trace

Submit form
path:PathWidget->Path alias entity -> validate
Pathvalidator->isValid(path)
  => getUrlIfValid($path)
  => getUrl($path, true=access_check)
  => getPathAttributes($path, ... true) => return false
        => accessAwareRouter=>match($path)
              Creates a request object from the path (=node path)
              access_result = accessmanager->checkRequest()
                Result = allowed
                => foreach checks
                     node->access(view) => this returns neutral !!
                => return andIf ($results) => allowed andif neutral = neutral => not allowed
=> Why is node access giving us neutral back ???
              !access_result-is_allowed()  => throw AccessDenied
node->access => parent->access => access control handler
NodeAccessControlHandler
=> bypass node access => allowed
=> !access content => forbidden
=> invoke(entity_access)
=> invoke(node_access)
mschudders’s picture

Version: 8.8.0 » 8.8.1

Update:
Solution in our case was adding a "nid=0" record in node_access

This seemed to be gone from the DB ...

 $ifRecordZeroExists = $db->select('node_access', 'na')
    ->fields('na', ['nid'])
    ->condition('nid', 0)
    ->condition('realm', 'all')
    ->execute()->fetchAll();

  if (empty($ifRecordZeroExists)) {
    // Populate the node access table.
    $db->insert('node_access')
      ->fields([
        'nid' => 0,
        'gid' => 0,
        'realm' => 'all',
        'grant_view' => 1,
        'grant_update' => 0,
        'grant_delete' => 0,
      ])
      ->execute();
  }
ulfg’s picture

We had the same problem.
As suggested in #15 i added two records for nid '0' (one 'en' and one 'sv')
Translating started working again immediatly.

Thank you for easy solution!

lowfidelity’s picture

Thanks Mschudders, #15 worked perfectly on a site that had that problem. So far I didn't see any side effects.

I manually added the entries to the database:

drush sql-cli

INSERT INTO node_access (nid, langcode, fallback, gid, realm, grant_view)
VALUES (0, 'de', 1, 0, 'all', 1);

INSERT INTO node_access (nid, langcode, fallback, gid, realm, grant_view)
VALUES (0, 'fr', 0, 0, 'all', 1);

mysql> select * from node_access where nid = 0;
+-----+----------+----------+-----+-------+------------+--------------+--------------+
| nid | langcode | fallback | gid | realm | grant_view | grant_update | grant_delete |
+-----+----------+----------+-----+-------+------------+--------------+--------------+
|   0 | de       |        1 |   0 | all   |          1 |            0 |            0 |
|   0 | fr       |        0 |   0 | all   |          1 |            0 |            0 |
+-----+----------+----------+-----+-------+------------+--------------+--------------+

Worked instantly without any cache rebuilding whatsoever.

Thanks for your hint!

sneo’s picture

Modify the databse do the trick for me too. Argh , i should have passe hier before scuba diving into the code like a maniac !! Thx !!

sneo’s picture

After more investigation, I made a module witch extend acces control on node.
The mistake i made is not to add langcode to each node access records I generate.

So after retriving all langcode of the website (3 lang), i the generate a grant for each langcode

exemple in hook_node_access_records

$grants = [];
$langs = \Drupal::languageManager()->getLanguages();
foreach ($langs as $langcode=>$lang) {
  $grants[] = [
    'realm' => "whatever custom realm",
    'gid' => 1,
    'grant_view' => 1,
    'grant_update' => 1,
    'grant_delete' => 0,
    'langcode' => $langcode
  ];
}

and it work like a charme. So maybe there is a module who is redefining the access rules and not defining the langcode

The problem with modifying directly the DB is that it's not a permanent solution, because the node access are rebuild sometime.

kriboogh’s picture

The problem is actually the alias field that is being defaulted to the original alias when creating a new translation. When we leave that empty (as it is the case when creating a new node), the alias is not validated and created with the correct alias patterns and language.

Note: that adding the default entry in the database when using modules that use the node_grant system might in some cases lead to side effects and the modules decision might be ignored since a global grant is found in the access table.

fox mulder’s picture

#20 solved the problem for us, thanks

lowfidelity’s picture

Thanks for that hint about the side effects, @kriboogh. Haven't noticed any yet with #15, but I'll give your patch asap a shot.

igonzalez’s picture

#20 Works for me

jeanyvesberger’s picture

#20 Works for me aswell. Thanks.

ant1’s picture

Status: Active » Needs review

Set status on 'Needs review' for better visibility in the issue queue.

embeau’s picture

#20 works for me too! Thanks!

shaktik’s picture

Issue tags: +Srijancontribution2020

#20 Work fine!

cobenash’s picture

#20 works fine. Thanks

Eduardo Alvarez’s picture

#20 works for us, please promote it to be included in a next core release.

weseze’s picture

I don't think this is a core issue and the patch from #20 seems to hide another issue, possibly with contrib modules.

Tested this with a clean install D8.8 and the problem is not present. Also tested with a D8.7 that was update to D8.8 and the problem is not present.

But I ran into this issue with sites that had access control modules enabled. Specifically in our case the adva module. The earlier suggestions to add node access records to the database also seem to hide the real issue.

nikita_tt’s picture

+1 to #30

The main problem here is that access records are not created for the just created translation at the moment access to the node (translated node) is being checked.

When the RouteMatch object prepares parameters for the route (\Drupal\Core\ParamConverter\EntityConverter::convert) it gets the node translation instead of the original node. BTW: the node translation has status TranslationStatusInterface::TRANSLATION_CREATED - this may be used for the future fix.

#19 works for me as a workaround.

kriboogh’s picture

But, when creating a new translation, there is no point for the alias from the original node to be taken, unless I'm missing something here.
The issue in #30 and #31, about access records are not created when a translation is created, should maybe be resolved in a different ticket? And the solution in #19 also exposes a different problem, mainly (contrib) modules not registering access records correctly by ommiting a langcode.

vannergard’s picture

Version: 8.8.1 » 10.0.x-dev

We are having this issue on 8.7 but only for nodes using content moderation, so it is possible it relates to this.
It implies either content moderation or the content_moderation_notifications contrib module

(Overall I have noticed a lack of testing of this combination of translations and content moderation)

rgpublic’s picture

Aha. Found it. The problem is indeed if hook_node_access_records is implemented without setting a langcode. You can search your custom modules folder for "hook_node_access_records". In my case, the problem was the "view_unpublished" module:

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

There is:
* 8.x-1.0-alpha1 4 January 2017
* 8.x-1.x-dev 12 Feb 2017

Only a month apart. Can't be that much of a difference, or can it? But if you download the ZIP and check the .module file, you can see immediately, that the langcode is not the set for the alpha version, but for the dev version.

So, for view_unpublished, the solution is to simply install the dev version. Perhaps this will also hint you in the right direction if you have problems with other contrib modules.

jchatard’s picture

Hi!

Just to tell that:

- on Drupal core 8.9
- no module view_unpublish
- nodes are not translations, they do have a language set
- does not occur on newly created nodes (never)
- does not occur on previously created nodes which are published
- DOES occur on previously created nodes which are unpublished <-- BUG

Is this related to an access_check entity stuff?

jchatard’s picture

@VAnnergard Why does this issue was bumped to 10.x ?

It seems to me it belongs to 8.x and 9.x.

ressa’s picture

Version: 10.0.x-dev » 8.9.x-dev

Restoring Version, after only branches and meta-branches are selectable in Drupal issues, see #3152808: Version field seems suboptimal for more.

finex’s picture

Patch #20 also works for me on 8.9.1. Thank you!

weseze’s picture

Patch #20 does not fix bug reported in #35. Bug reported in #35 has got nothing to do with access records. Seems to be actual bug in core somewhere.

kriboogh’s picture

#35 should have it's own ticket. Like I said in #32, there are several things wrong in core that should each be addressed separately. #20 (as far as I see) fixes the original topic, the problem with the invalid path. A new translation should not get the path from the source, as a new path will be created upon saving it.

kbriand’s picture

It seems that when a module implements hook_node_access_records, a database query is run on the node_access table (when translating a node). It looks for a row having the node id and the target translation language, which does not exist yet. Does anybody still have the issue, even with patch from #20 and view_unpublished in its last version (or any other module implementing hook_node_access_records)?

igonzalez’s picture

Patch #20 also works for me on 8.9.6 Thank you!

arthur_lorenz’s picture

#20 saves the day. Patch works also for me on 8.9.6, thanks a lot!

jasonluttrell’s picture

#20 did not work for me. I get the Either the path '/user/1' is invalid or you do not have access to it. error message on our password reset page after updating password (when still anonymous--using Simple Password Reset module). URL is something like /user/reset/1/token_string. The only thing that makes this error go away is to un-install pathauto. I'm not sure why, but this is the only solution that works for me at the moment. (Drupal 9.0.7 and Pathauto 1.8.) So maybe there are different causes. I only mention this in case anyone else has run into this issue. Thanks.

Cross-posted here as well: https://www.drupal.org/project/pathauto/issues/3107695#comment-13895921

bogdog400’s picture

#20 doesn't work for me. Drupal 9.0.7 without Pathauto. Nor does adding the rows to the db as in #17.

igonzalez’s picture

Patch #20 also works for me on 8.9.9

igonzalez’s picture

Priority: Major » Critical
a.hover’s picture

I was having the same issue and I realised it was because we hadn't got "URL alias" set to translatable for all our content types via Configuration > Regional and language > Content language and translation (/admin/config/regional/content-language).

This didn't used to be an issue - presumably it's something that has reared itself since path aliases were transitioned to be entities (something which I believe happened in an 8.8 update).

Just commenting this here in case it helps anyone else!
I did also require the patch from #20.

luksak’s picture

@rgpublic I can't confirm your comment in #34. I am on the latest release of view_unpublished and I am still facing this issue. Or do you mean that the patch and the leatest release of view_unpublished is needed to fix this?

The patch in #20 fixes the issue for me.

chris matthews’s picture

I don't have translated nodes, but I still run into this issue on Drupal Core and 8.9.13 and Pathauto 8.x-1.8. I also don't have view_unpublished installed/enabled as others have referenced.

chris matthews’s picture

The suggestion in #3107695: Drupal 8.8.1 issue Either the path '/node/123' is invalid or you do not have access to it. #10 worked for me. Although it's not really a fix

In case anyone else runs into this issue, a "quick fix" for me was to go to the Administration > Configuration > Search and metadata > URL aliases > Settings page (/admin/config/search/path/settings) and under "Enabled Entity Types" uncheck User.

rgpublic’s picture

@Lukas von Blarer: No, I meant that the latest release is sufficient. Back then, there was no stable release. Currently there's 1.0 stable out. In view_unpublished.module there's a function view_unpublished_node_access_records, containing this (comment added by me):

      $access_content_grants[] = [
        'realm' => 'view_unpublished_published_content',
        'gid' => 1,
        'grant_view' => 1,
        'grant_update' => 0,
        'grant_delete' => 0,
        'langcode' => $langcode,  //<=== This is here is important
      ];

If you have that line, than I *guess* view_unpublished isn't the culprit anymore, but you might want to search/grep through all your modules' code for the string "_node_access_records" if there are other modules which also modify access_records. It is not too far-fetched I guess that other modules might suffer from the same problem.

Since my comment back then, many others have written sth. along the lines of "Hey, my view_unpublished is up-to-date/not installed...", but they never explicitly stated: "I also don't have any other modules implementing the access_records hook". That would have been more useful. Only if that's the case, we are obviously really looking at an additional cause of the same effect.

allaprishchepa’s picture

StatusFileSize
new1.08 KB

Actually the patch #20 not solve the issue, it just helps to prevent node access checking while generating the alias.
But if the URL alias field is allowed to be edited, then the User should be able to save custom alias. But in this case, the node access checking will be executed again and the User won't be able to save the translation because of this error.

I've created a patch for NodeGrantDatabaseStorage. I've added a code, it uses the original node's language for access checking when the current node is in translating process.

allaprishchepa’s picture

catch’s picture

Issue tags: +Needs tests

@allaprishchepa are the steps in the issue summary still accurate? Do you think you could add some test coverage based on those?

tvalimaa’s picture

#53 seems to fix my problem...

robertom’s picture

tnx @allaprishchepa

#53 fix my problem

agentrickard’s picture

Status: Needs review » Needs work

Technically, this query should be using the 'fallback' column in the {node_access} table. That column is expressly designed for the case of "We need to check access for a node which has not yet been translated."

By default, that is the original node, but it doesn't have to be.

See the pattern in NodeGrantDatabaseStorage::alterQuery().

        // Add langcode-based filtering if this is a multilingual site.
        if ($is_multilingual) {
          // If no specific langcode to check for is given, use the grant entry
          // which is set as a fallback.
          // If a specific langcode is given, use the grant entry for it.
          if ($langcode === FALSE) {
            $subquery->condition('na.fallback', 1, '=');
          }
          else {
            $subquery->condition('na.langcode', $langcode, '=');
          }
        }

The issue seems to be that the access() method is using a raw database->select() rather than an EntityQuery and therefore it is missing this logic.

flyke’s picture

StatusFileSize
new69.77 KB

#53 fixed problem for me as well.
Attached screenshot (drupal-pathauto-error-on-save.png) is before using patch 53 when non admin user tries to translate content. After applying patch #53 everything works okay.

agentrickard’s picture

Patch #53 doesn't use the core database schema correctly and is not valid.

agentrickard’s picture

Status: Needs work » Needs review
StatusFileSize
new1.23 KB

New patch, using the fallback column if the langcode is not set.

I do wonder if the IF condition is correct.

$langcode = $node->isNewTranslation() ? NULL : $node->language()->getId();

Are there other conditions that would cause langcode to be empty?

tvalimaa’s picture

#61 Patch not working for me. I get PHP Parse error.

  • Build project composer install
  • Sync project database
  • drush cr gives me error:

PHP Parse error: syntax error, unexpected '->' (T_OBJECT_OPERATOR) in /app/web/core/modules/node/src/NodeGrantDatabaseStorage.php on line 92

jrochate’s picture

Same error here. 8.9.13 when applying #61

agentrickard’s picture

This is what I get for coding without looking....

Sorry about that.

jrochate’s picture

:) Thanks.

bachbach’s picture

#64 fixed my probleme, thank you

igonzalez’s picture

#64 works for me, thank you

mandclu’s picture

Status: Needs review » Reviewed & tested by the community

I ran into this same issue, and the provided patch solved it, using Drupal 9.1.5. Marking this as RTBC though I suspect it will need to go through additional steps.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

We need to address #55. In order to commit a bug fix, we need an automated test to prove that we've fixed the bug and ensure that we don't break it again in the future. For more information about writing tests in Drupal, see the following links:

  1. https://www.drupal.org/docs/testing/phpunit-in-drupal/phpunit-javascript...
  2. https://api.drupal.org/api/drupal/core%21core.api.php/group/testing/9.1.x
keescornelisse’s picture

Patch #64 works also at Drupal 9.1 :-).

kunalkursija’s picture

  • I faced the same issue in Drupal 8.9.15.
  • Tried the patch from #64 and it seems to be fixing the issue.
francescbassas’s picture

#64 works for me, thank you

tinto’s picture

Patch #64 solves the problem for me.

Install is running on Drupal 9.1.9.

drupix’s picture

Patch #64 solves the problem for me on Drupal 9.2.4

Thank you!

avpaderno’s picture

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8.9.x is open only to security issues, now.

tonihoo’s picture

Patch #64 worked in Drupal 9.2.6. Thanks a lot!

flyke’s picture

#64 did not work for me in a particular project, instead enabling the permission 'Link to any page' did the trick.
On other projects #53 and later on #64 do seemed to work.

alphex’s picture

Replying to #77
This fixed it for me also.
The patch in #64 did not work for me.

I have content in content moderation.
"Presenters" can create a "Poster"
and once its saved, they can't view it any more... SO I think its choking on trying to save and load the /node/NID ? or check access to it?

The error I get is : Either the path '/node/XXX' is invalid or you do not have access to it.

Now I need to figure out how to let the PRESENTER view their DRAFT content...

alex.bukach’s picture

Version: 9.2.x-dev » 9.3.x-dev
Assigned: Unassigned » alex.bukach
Status: Needs work » Needs review
StatusFileSize
new3.11 KB
new3.11 KB

I have another point of view on to this issue. The problem is that Drupal\path\Plugin\Field\FieldWidget\PathWidget::validateFormElement() sets the form error even if the field is not accessible by user while it should not.

As an example of how this actually should be handled is Drupal\Core\Field\WidgetBase::flagErrors(): it sets errors only if the element is visible, an we should follow the same approach here.

alex.bukach’s picture

alex.bukach’s picture

StatusFileSize
new2.93 KB
mxr576’s picture

I agree with Alex's reasoning at #81. The fix in #82 works fine, although in the attached test I would rather (just) validate the form submission works by asserting the expected positive result (e.g.: I am on the node view) instead of asserting that some error message is not visible - which may change in the future and makes this test unstable that provides false-positive confirmation.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

igonzalez’s picture

#82 works for me in 9.3.2

gngn’s picture

Using 8.8.11 (yeah, I know...) #82 works for me.
But #20 also allowed to translate the node.

So I am not sure which one to use...
To me Alex Bukach's reasoning in #81 sounds convinving - so I think I will use #82.

avpaderno’s picture

Assigned: alex.bukach » Unassigned
catch’s picture

Status: Needs review » Needs work
Issue tags: +Bug Smash Initiative, +Needs issue summary update
+++ b/core/modules/path/tests/src/Functional/PathNoAccessTest.php
@@ -0,0 +1,64 @@
+
+    // Make sure path validation error is not thrown.
+    $page_text = strip_tags($this->getSession()->getPage()->getText());
+    $error_text = "Either the path '/node/{$node->id()}' is invalid or you do not have access to it.";
+    $message = sprintf('The text "%s" appears in the text of this page, but it should not.', $error_text);
+    $this->assertEquals(strpos($page_text, $error_text), FALSE, $message);
+

This needs a positive assertion so that it fails even if the strings change. Would also be good to update the issue summary given there are at least three conflicting approaches on this issue.

quietone’s picture

Issue summary: View changes

Just adding the standard template.

quietone’s picture

Issue summary: View changes

Updating the IS. I am leaving the tag until someone more familiar with this issue reviews it.

crzdev’s picture

Hi, just #20 worked in a case where using translatable published (status) property (with revisions & content moderation with draft content) & using https://www.drupal.org/project/drupal/issues/3162934#comment-13778665 patch to prevent not accesible published translations when saving a not published (draft) translation.
More details about complete use case into https://www.drupal.org/project/drupal/issues/3162934#comment-14409973 comment.

ricovandevin’s picture

The patch from #82 is not working in our case. We have the error but the URL alias field is visible in our setup. Both leaving the path alias untouched for the translation and changing it leads to the error.

Patch from #64 does prevent the error from occurring. Using that one for now.

quietone’s picture

I tested this on standard install of Drupal 9.4.x in Italian and using the steps to reproduce in the issue summary I was not able to reproduce the problem. I tried again on Drupal 8.9.15.

Adding tag for needing steps to reproduce.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

hoebekewim’s picture

To be able to have this issue, enable the https://www.drupal.org/project/view_unpublished module.
Patch #64 fixes the issue.

flyke’s picture

I can confirm that I use the view_unpublished module in my projects too.

ikeigenwijs’s picture

we dont use the view_unpublished module in the projects that has this issue.

dravenk’s picture

@quietone Reply #93
Hi, I have the same issue. It's reproduced when content has any translation in moderated (content_moderation module) status can't be modified both.
1. The content has English and Chinese two versions. The path alias have been created.
2. Change the Chinese version moderated status to unpublish.
3. Edit the English version and save. The page result below

Error message
Either the path '/node/xxx' is invalid or you do not have access to it.
ravi.shankar’s picture

Status: Needs work » Needs review
StatusFileSize
new2.96 KB
new1016 bytes
new1.93 KB

Added positive assertion as per comment #88, addressed Drupal CS issue and added test only patch as well.

The last submitted patch, 99: 3101344-99.patch, failed testing. View results

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nicrodgers’s picture

Status: Needs review » Needs work

Setting back to Needs Work, as the patch in 99 failed, and the test-only patch passed but should have failed.

flyke’s picture

3101344-99.patch doesnt fix it for me.

My project is currently on Drupal 9.5.3.
The patch applies without problem.

The project has 3 languages:
- NL (Dutch) -> is the default language
- FR (French)
- EN (English)

The client/content can successfully create a new node of any type in any language, whether its the default language (NL) or another.
When he tries to create a translation, he gets the error:
Either the path '/node/123' is invalid or you do not have access to it

The other patches here also did not fix this error.
I also tried this but that did not fix it either.

If you are in a pinch like me and you need a quick fix for your project until this is actually fixed, then edit the permissions of the role that is having this problem and give it the 'Link to any page' permission. Please make a calculated risk assesment of your specific case of the implications of giving that permission before you do that. But if you do, then the problem is (temporary) fixed and when there finally is a working patch you can revoke that permission again.

flyke’s picture

StatusFileSize
new350.76 KB
new123.38 KB

In my case, editing a translation via 'Edit translations' does not work, which has this path structure:
/node/123/translations/edit/en
But editing the translation directly via admin/content does work, which has this path structure:
/node/123/edit?language_content_entity=en

Even as admin user, the /translations/edit link does not work while the ?language_content_entity edit link does.

I cannot set language detection and selection to language via url parameter for this project, as this project relies on domain module and country path module. So we have a combined url part that indicates both the country and the language, like /be-nl/node/123 (dutch version of the node) and /be-fr/node/123 (french version of the node).
So the part 'be-nl' is not a language code and we do not want the structure to be like /be-nl/nl/node/123.
So the language detection and selection settings are probably causing this behaviour.
Content language detection is set to:
- Content language (Determines the content language from the request parameter named 'language_content_entity'.)
- Domain language (Language based on the current domains language settings)

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

daften’s picture

In our case, the patches that work on \Drupal\path\Plugin\Field\FieldWidget\PathWidget::validateFormElement don't work, because the widget is active. Having the widget active should not keep this bug active. I don't agree Alex, this is not a problem present because of a widget, is an underlying issue in the node_grants system.
The patch from #64 fixes it for us.

jasloe’s picture

FWIW, #64 resolves this issue for me on a multilingual Drupal 10.0 site.

Before applying the patch, users with correct node editing and translation permissions attempting to create a new translation receive the following message...

Either the path '/node/[some-nid]' is invalid or you do not have access to it.

...no message is written to the error log.

frankdesign’s picture

Patch at #64 fixes for me with 10.1.2. I also have View Unpublished installed.

quietone’s picture

Status: Needs work » Needs review
Issue tags: -Needs issue summary update

I tried to reproduce this Drupal 10.1.x using the steps in the Issue Summary (again) and in #98 and was not able to.

I did update the patch, making the change asked for in #88. Also made changes to comments and switched to an MR.

smustgrave’s picture

Status: Needs review » Postponed (maintainer needs more info)

Also have not been able to reproduce. Could someone confirm this is still an issue in D10?

t_d_d’s picture

Status: Postponed (maintainer needs more info) » Needs review

Still an issue on D10 (10.1.6).

Not sure if it was mentioned before but for reproducibility, in my case this bug only manifests itself when creating translation from interface language different from original node language. For example, while this /en/node/276/translations/add/en/cs works (adding translation for originally EN node from EN interface), this does not /cs/node/276/translations/add/en/cs (adding translation for originally EN node from CS interface - and this is path which button to add translation uses).

smustgrave’s picture

Status: Needs review » Needs work

Confirmed steps should be added to the IS.

Alsolast MR has test failures.

t_d_d’s picture

Issue summary: View changes

Updated steps to reproduce in IS with point mentioning interface language being important when trying to reproduce bug.

borisson_’s picture

The steps to reproduce that are in this issue are not sufficient. I can't reproduce the problem with these steps, I tested this on 11.x

  1. Use sth. other than the administrator account. You should have the usual editor permissions to create nodes and create/update translations and translate any entity, of course. You should not have any url alias permissions.
  2. Create a new node in the original language (in my case: German)
  3. Save the node
  4. Edit the node again
  5. Click on translation, add translation (English)
  6. Site interface of translation form should be now in target (English) language (e.g. path /en/node/123/translations/add/de/en)
  7. Try to save
borisson_’s picture

I just had @Mschudders reproduce this, as we are sitting next to each other at the moment. They can reproduce it on their instal without issues, but that is not a core checkout but rather a site with a bunch of contrib modules enabled.
I think this is only a problem with a certain set of contrib modules?

mschudders’s picture

StatusFileSize
new198.17 KB

Adding screenshot which will help in debugging/finding the issue:
Problem debug

EDIT:

/over-ons/azaza > is the DUTCH alias.
Which is being used in FR validation part.

---

Might need to set-up aliasses on a clean Drupal to have the same "problem".

borisson_’s picture

Even with pathauto installed and a configuration for articles, I can't trigger the error.

tinto’s picture

I've seen this problem on one of our client sites too. Perhaps @Mschudders and I could compare a list of contrib modules installed so we can see which modules we both have enabled and narrow down which is the culprit?

akhil babu’s picture

As mentioned in some of the previous comments, this bug occurs whenever any contrib/custom module implements hook_node_grants()

Here is how I reproduced this issue in Drupal 10.2

  • Install with demo_umami profile
  • Give "Editorial workflow: Use Create New Draft transition" and "Article: Create new content" permissions to the editor role.
  • Check the node_access table. There will be only one entry with nid 0 which is the default record.
  • Create a custom module and implement hook_node_grants(). Install the module.
/**
 * Implements hook_node_grants().
 */
function my_module_node_grants(AccountInterface $account, $operation) {
  $grants = [];

  return $grants;
}
  • Login as admin and visit any admin page. There will be a message to rebuild the permissions. Click on Rebuild permissions to rebuild all permissions.

https://www.drupal.org/files/issues/2024-01-17/3101344-rebuild%20permissions.png

  • Login with any of the editor accounts (Eg: uid=3) in incognito mode.
  • Add an English article. Give a path in URL alias field and publish it.

https://www.drupal.org/files/issues/2024-01-17/3101344-create-article.png

  • Try to add spanish translation.

https://www.drupal.org/files/issues/2024-01-17/3101344-translation-error.png

akhil babu’s picture

akhil babu’s picture

Patch #99 will only work if "URL alias" field is not rendered in the edit form (ie: User does not have 'Create URL alias" permission) as it skips the validation completely. It wont work if the field is accessible to the user.

I think patch #64 is the best way to fix this bug and here is why:-

validateFormElement() method in Drupal\path\Plugin\Field\FieldWidget\PathWidget invokes validations whenever there is an entry in the "URL alias" field. This eventually calls access() method in NodeGrantDatabaseStorage. This method checks if any modules have 'hook_node_grants' implementations and, if so, it checks the node_access table for access grants. The db query uses current language code of the node as a condition.

The "node_access" table is updated only when nodes are published. If you check the node access table now, there will be only one entry for node with id '20' (The one created in previous step) and language code will be 'en'.

https://www.drupal.org/files/issues/2024-01-17/3101344-node-access-table.png

When we try to save the spanish translation, code checks the table with 'es' language code. There won't be any entry and access() method returns AccessResult::neutral()

This result is eventually passed to Drupal\Core\Routing\AccessAwareRouter checkAccess(). This method throws AccessDeniedHttpException if access is not allowed which causes the validation error.

akhil babu’s picture

StatusFileSize
new224.99 KB
akhil babu’s picture

Translations can be added without any errors if the original English content is kept in draft state. In this scenario also, there won't be an entry in the node_access table for the new node in both 'en' and 'es' languages. So access() method in NodeGrantDatabaseStorage would still return neutral access. But access checks also invoke 'content_moderation_entity_access' and it returns AccessResult::allowedIfHasPermission($account, 'view any unpublished content'). So user with 'view any unpublished content' permission would be able to save the translation. Later both translations can be published and updated without any errors.

akhil babu’s picture

Access check in NodeGrantDatabaseStorage queries the node_access table to decide the access only when hook_node_grant is implemented. So access() in NodeGrantDatabaseStorage should be able to provide proper access result.

Patch #64 fixes the error by checking the fallback value if the translation is new.

Committing that patch as an MR. Will also add a test to show the bug.

akhil babu’s picture

StatusFileSize
new52.2 KB

Added the test

https://www.drupal.org/files/issues/2024-01-17/3101344-test-fail.png

"Spell-checking" is failing with the message
/scripts-124254-649588/step_script: line 277: /usr/bin/tr: Argument list too long
/scripts-124254-649588/step_script: line 277: /usr/bin/yarn: Argument list too long
Moving ro "Needs review" for reviewing the fix.

akhil babu’s picture

Status: Needs work » Needs review

Akhil Babu changed the visibility of the branch 11.x to hidden.

akhil babu’s picture

Title: Cannot save translated nodes after upgrading to 8.8 due to invalid path » hook_node_grants implementations lead to a 'URL Alias' validation error when saving translated nodes.
Issue summary: View changes
akhil babu’s picture

Issue summary: View changes
akhil babu’s picture

Issue summary: View changes
akhil babu’s picture

Issue summary: View changes
dqd’s picture

The issue is full of very useful comments and brainstorming hooks helping to get a good picture of why it can't be reproduced every time, etc. Great work in here and Thanks @Akhil Babu! +1 for your further steps and information provided in the last comments and working further on a fix. Wake up call for all of us.

smustgrave’s picture

Just fyi helps to hide the old patches and MRs. There is a new section in the standard template for which MR to review but its new so not surprised it isn't here. Have hidden the patches for clarity

Ran the test-only features

1) Drupal\Tests\path\Functional\PathWithNodeAccessGrantsTest::testAliasTranslation
Behat\Mink\Exception\ResponseTextException: The text "Basic page test has been updated." was not found anywhere in the text of the current page.
/builds/issue/drupal-3101344/vendor/behat/mink/src/WebAssert.php:811
/builds/issue/drupal-3101344/vendor/behat/mink/src/WebAssert.php:262
/builds/issue/drupal-3101344/core/modules/path/tests/src/Functional/PathWithNodeAccessGrantsTest.php:102
/builds/issue/drupal-3101344/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
ERRORS!
Tests: 1, Assertions: 22, Errors: 1.

Left 2 small comments on the MR but overall looks good.

quotientix’s picture

Patch in #64 works for me in 10.2.2 - thanks for the team effort here!

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Feedback appears to have been addressed.

catch’s picture

Status: Reviewed & tested by the community » Needs work

One question on the MR.

akhil babu’s picture

Status: Needs work » Needs review

Feedback addressed. Moving back to needs review.

smustgrave’s picture

Status: Needs review » Needs work

If going to do that way probably don't need the $langcode variable anymore.

akhil babu’s picture

Status: Needs work » Needs review

Sure. $language variable was unnecessary, so I've removed it.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Feedback appears to be addressed.

  • catch committed e6fe4180 on 10.2.x
    Issue #3101344 by Akhil Babu, Alex Bukach, ravi.shankar, quietone,...

  • catch committed f665483c on 11.x
    Issue #3101344 by Akhil Babu, Alex Bukach, ravi.shankar, quietone,...
catch’s picture

Good to see this one ready. I did my best with issue credit but there are a lot of comments on this issue so apologies if anyone got overlooked.

Committed/pushed to 11.x and cherry-picked to 10.2.x, thanks!

catch’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

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