Setting URL alias without '/' prevents all article edits

Created on 7 May 2025, 26 days ago

Overview

When creating a new page within an Article and setting its URL alias without the leading slash (e.g., testpage1 instead of /testpage1), throws an error:
"An unexpected error has occurred while fetching layouts."

This issue not only affects the current page but also prevents editing of any other Article pages, even if the problematic page is deleted.

  1. Edit an existing Article
  2. From the navigator, create a new page and set the title to Test page 1.
  3. In the right-hand section, add a URL alias as testpage1 (Do not add a leading "/").
  4. Observe the error message: "An unexpected error has occurred while fetching layouts."
  5. Try editing any other Article โ€” the error persists.
  6. Even after deleting all existing articles and creating new ones, the issue still remains.

Proposed resolution

User interface changes

๐Ÿ› Bug report
Status

Active

Version

0.0

Component

Page builder

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @mayur-sose
  • Error in browser console

    {
        "message": "assert(str_starts_with($autoSavePath, '/'))"
    }
    
    {
        "status": 500,
        "data": {
            "message": "assert(str_starts_with($autoSavePath, '/'))"
        }
    }
    
  • Below is the code to fix the issue :

    -          assert(str_starts_with($autoSavePath, '/'));
    +          // Ensure autoSavePath starts with '/'
    +          if (!str_starts_with($autoSavePath, '/')) {
    +            $autoSavePath = '/' . ltrim($autoSavePath, '/');
    +          }
    
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia Akhil Babu Chengannur

    Rather than adding '/' to paths that dont start with it, we should add validation to the entity form fields

    Validation for entity fields are not yet impletemted
    file: experience_builder/ui/src/components/form/inputBehaviors.tsx

      const validateNewValue = (e: React.ChangeEvent, newValue: any) => {
        // @todo Implement this.
        return { valid: true, errors: null };
      };

    This should be updated to

      const validateNewValue = (e: React.ChangeEvent, newValue: any) => {
        const target = e.target as HTMLInputElement;
        if (target.id === 'edit-path-0-alias' && typeof newValue === 'string') {
          if (newValue && !newValue.startsWith('/')) {
            return {
              valid: false,
              errors: [
                {
                  keyword: 'value',
                  instancePath: '',
                  schemaPath: '',
                  params: {},
                  message: 'The alias path has to start with a slash',
                },
              ],
            };
          }
        }
        // @todo Implement for other entity fields.
        return { valid: true, errors: null };
      };
  • Pipeline finished with Failed
    26 days ago
    #491070
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia meghasharma

    Thanks @akhil for the input!
    You're right โ€” adding frontend validation makes sense for better UX and to prevent invalid input early on. I'll update the PR to include this validation inside validateNewValue().

    Also, I think we can keep the backend fallback (str_starts_with) check just to be safe in case any invalid alias somehow bypasses the UI (e.g., via API or future form changes).

    Let me know if you'd prefer removing the backend fallback.

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia meghasharma

    Right now Iโ€™ve added backend validation to ensure alias starts with /, which resolves the layout error.
    Also noticed that the error message โ€œThe alias path has to start with a slashโ€ is already being shown in the UI if / is missing โ€” but the page still gets saved.
    Should I go ahead and update the frontend logic to block submission if the alias is invalid?
    Attaching the screenshot.

  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland lauriii Finland
  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland lauriii Finland

    It looks like it's actually an assert that's triggering this. Changing to major because of that.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    @akhil babu in #5:

    Rather than adding '/' to paths that dont start with it, we should add validation to the entity form fields

    ๐Ÿ’ฏ

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia meghasharma

    Updated the patch to add client-side validation to ensure alias starts with /.
    However, currently weโ€™re still able to publish even if the alias doesnโ€™t start with /
    Attaching screenshot to show the client-side error.

  • Pipeline finished with Failed
    24 days ago
    Total: 875s
    #492970
  • ๐Ÿ‡ช๐Ÿ‡ธSpain penyaskito Seville ๐Ÿ’ƒ, Spain ๐Ÿ‡ช๐Ÿ‡ธ, UTC+2 ๐Ÿ‡ช๐Ÿ‡บ

    @meghasharma I'm pretty sure the publish issue is because of ๐Ÿ“Œ Publish checks validation constraints, but not form validation Active , so you shouldn't need to worry about that here.

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia meghasharma

    Thanks @penyaskito for the clarification!
    Yes, the client-side validation is now working correctly and shows an error when the alias does not start with /.
    Since the publishing behavior is related to #3521759 and not this issue, Iโ€™m moving this back to Needs review.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States bnjmnm Ann Arbor, MI

    Over the past few months there were a few discussions where concerns expressed about having JSON schema validation occur on both the back and front ends, because even though they are evaluating the exact same schema, there is the potential for a difference because the validation is performed by different validators. For that specific situation I think there's far more benefit to using the two validators than the risks it introduces. For this MR, however, I'm not sure yet if the tradeoff is worth it.

    What I'm seeing here is significantly more bespoke than the above, and could be more difficult to defend. In this case, it's hand-replicating a property constraint already defined in \Drupal\path_alias\Entity\PathAlias::baseFieldDefinitions, and it's doing it based on field name vs something more generalized. In the case of path this might be fine

    A more scalable approach might be converting regex property constraints like this to HTML5 pattern attributes and possibly using setCustomValidity for the messages. If such an approach doesn't happen, at the very least there should be some documented justification why both the replication of logic and the name based implementation are acceptable over a more scalable/abstracted approach to avoid unwanted precedence setting.

    TLDR

    • Ideally we'd find a way to translate existing constraints to html attributes
    • If the more bespoke approach is used , there should at least be justification comments accompanying the code
  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland lauriii Finland

    I'm proposing to add a new widget for generated URL Aliases in โœจ Creating a page generates the URL path dynamically when editing. Active for better authoring UX. I wonder if this validation could be added on top of that?

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    #20++ โ€” great write-up, @bnjmnm! ๐Ÿ˜Š

    Ideally we'd find a way to translate existing constraints to html attributes

    Couldn't agree more! ๐Ÿ‘

    โœ… Server-side validation constraint

    Actually, the path alias field does have the necessary RegEx constraint defined already โ€” \Drupal\path_alias\Entity\PathAlias::baseFieldDefinitions() contains:

        $fields['alias'] = BaseFieldDefinition::create('string')
    โ€ฆ
          ->addPropertyConstraints('value', [
            'Regex' => [
              'pattern' => '/^\//i',
              'message' => new TranslatableMarkup('The alias path has to start with a slash.'),
            ],
          ]);
    

    (Since #3007832: Convert custom path alias forms to entity forms โ†’ .)

    โœ… Transforming from one schema to another

    We've already got JSON schema `type: string, pattern: โ€ฆ` โ†’ Symfony RegEx constraint transformation logic in
    \Drupal\experience_builder\JsonSchemaInterpreter\JsonSchemaType::toDataTypeShapeRequirements():

            array_key_exists('pattern', $schema) && array_key_exists('format', $schema) => new DataTypeShapeRequirements([
              JsonSchemaStringFormat::from($schema['format'])->toDataTypeShapeRequirements(),
              // TRICKY: `pattern` in JSON schema requires no start/end delimiters,
              // but `preg_match()` in PHP does.
              // @see https://json-schema.org/understanding-json-schema/reference/regular_expressions
              // @see \Symfony\Component\Validator\Constraints\Regex
              new DataTypeShapeRequirement('Regex', ['pattern' => '/' . str_replace('/', '\/', $schema['pattern']) . '/']),
            ]),
    

    @bnjmnm is proposing to do the inverse. That's totally doable.

    โœ… Passing JSON Schema to the client per prop,

    We've already got this infrastructure since ๐Ÿ› Premature prop validation can break the UI Active : SDCs and code components are passing jsonSchema to the client.

    โŒ Passing JSON Schema to the client per prop,

    This part we don't have. How would you want that information to be passed to you?

    ๐Ÿค” Alternative proposal

    Or โ€ฆ actually, in this particular case โ€ฆ what if we avoided all that, and just altered \Drupal\path\Plugin\Field\FieldWidget\PathWidget to set the pattern attribute on the input[type=text] that was generated server-side?

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    Let's re-assess this after โœจ Creating a page generates the URL path dynamically when editing. Active lands. As @lauriii wrote in #21, this may not be necessary anymore then.

    @bnjmnm's analysis in #20 will likely apply to other field widgets later. Some parts of what I wrote in #22 will likely be still relevant then, too.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    โœจ Creating a page generates the URL path dynamically when editing. Active is in. I think we should now close this. Do you agree, @lauriii?

  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland lauriii Finland

    It would be nice to have client side validation for this still for UX purposes. Reducing priority.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    WFM, but given nothing is broken anymore, and this is now about enhancing, shifting to task rather than bug.

Production build 0.71.5 2024