Problem/Motivation

When a services.yml file is badly-formed, doing a container rebuild just gives you an error with a snippet of the problem:

> A colon cannot be used in an unquoted mapping value at line 4 (near " - { name: route_enhancer }").

It doesn't tell you which file went wrong.

Steps to reproduce

Proposed resolution

DrupalKernel::compileContainer() should wrap calls to YamlFileLoader->load() with a try/catch block, and rethrow the exception with additional information about the filename.

This should be done in DrupalKernel rather than YamlFileLoader, as YamlFileLoader should be kept as close as possible to the Symfony version of that class that is is a fork of.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork drupal-3283035

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

    joachim created an issue. See original summary.

    bruno.bicudo’s picture

    StatusFileSize
    new47.11 KB

    Just thinking here, but would something like this work? (just illustrating here)

          try {
            $yaml_loader->load($filename);
          }
          catch (\Exception $e) {
            \Drupal::logger('php')->error('The file ' . $filename . 'failed to load due to error: ' . $e->getMessage());
          }
    

    I don't know if it's a good approach (and what would be a good one XD). Any help is appreciated.

    joachim’s picture

    > catch (\Exception $e) {

    It might be a more specific exception we should catch -- what does YamlLoader throw?

    > \Drupal::logger('php')->error('The file ' . $filename . 'failed to load due to error: ' . $e->getMessage());

    We should throw a new exception, not log and carry on. If a services.yml is not parseable, then Drupal can't run.

    longwave’s picture

    Symfony now has some code to handle this: https://github.com/symfony/dependency-injection/blob/f0d7ec8b5d84e262498...

    We use a custom Yaml parser (which invokes PECL or Symfony as available) so we can't copy the code exactly. But I suggest we do copy the error message from Symfony so our YamlFileLoader is closer to theirs.

    bruno.bicudo’s picture

    @joachin You're right. We should halt the execution. Looks like it's throwing an InvalidDataTypeException atm. Should i keep it?

    @longwave i like the message from symfony.

    longwave’s picture

    I would catch the InvalidDataTypeException and throw InvalidArgumentException, as that is used for all other exceptions in YamlFileLoader - the filename argument is considered invalid because of a parse error, in this case.

    bruno.bicudo’s picture

    StatusFileSize
    new58.96 KB
    new58.75 KB
    new1.75 KB

    Ok so, we're catching InvalidDataTypeException here and throwing InvalidArgumentException in both load calls.

    I attached 2 screenshots showing the current error message and the "new" one.

    Hope it helps. Kindly review it :)

    bruno.bicudo’s picture

    Status: Active » Needs review
    longwave’s picture

    Thanks, the new message is a good improvement.

    Why don't we modify YamlFileLoader instead, then we only have to catch and throw once, in the same place as Symfony does?

    bruno.bicudo’s picture

    @longwave the reporter (@joachim) said at the issue summary:

    This should be done in DrupalKernel rather than YamlFileLoader, as YamlFileLoader should be kept as close as possible to the Symfony version of that class that is is a fork of.

    If you guys agree that YamlFileLoader is the best place to make the approach i can send another patch :)

    longwave’s picture

    I think as Symfony's YamlFileLoader added this since we copied it, it's OK to put the same (or at least very similar) code in our copy too.

    bruno.bicudo’s picture

    StatusFileSize
    new1.21 KB
    new2.63 KB

    Here's a new patch with the proposed approach in YamlFileLoader.

    I won't upload images this time as the messages remains the same.

    Hope it helps. Will keep in "needs review", kindly review it and choose whichever fits the goal better :)

    joachim’s picture

    Status: Needs review » Needs work

    Looking good, just needs a few small fixes:

    1. +++ b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
      @@ -425,7 +426,14 @@ protected function loadFile($file)
      +          $validFile = $this->validate(Yaml::decode(file_get_contents($file)), $file);
      

      Local variable names should be camel case, not pascal.

    2. +++ b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
      @@ -425,7 +426,14 @@ protected function loadFile($file)
      +        catch (InvalidDataTypeException $e) {
      

      That needs an initial backslash I think?

    3. +++ b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
      @@ -425,7 +426,14 @@ protected function loadFile($file)
      +          throw new \InvalidArgumentException(sprintf('The filea "%s" does not contain valid YAML: ', $file) . $e->getMessage());
      

      Typo: 'filea'.

    bruno.bicudo’s picture

    StatusFileSize
    new1.21 KB
    new731 bytes

    Oh my... Sorry for the typo there, i was in a hurry, my mistake.

    Ok so:

    #13-1: Pascal case would be like $ValidFile, while camel case stands for $validFile, am i wrong? I think the variable name in this case is already camel case.

    #13-2: InvalidDataTypeException doesn't need a backslash because it's already declared in an use statement under \Drupal\Component\Serialization\Exception\InvalidDataTypeException. Also thanks for pointing it, because i had used a backslash in InvalidArgumentException without noticing it was also declared in an use statement XD

    #13-3: Corrected the typo, thanks for pointing it :D

    New patch on it's way. Kindly review it :D

    bruno.bicudo’s picture

    Status: Needs work » Needs review
    joachim’s picture

    Status: Needs review » Needs work

    > #13-1: Pascal case would be like $ValidFile, while camel case stands for $validFile, am i wrong? I think the variable name in this case is already camel case.

    Sorry, I was commenting too late at night :/

    It should be snake case. Drupal coding standards say that local variables and function params are $snake_case.

    bruno.bicudo’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new1.21 KB
    new765 bytes

    No problem haha.

    This one fixes the variable name from camel case to snake case. Thanks for pointing it and for the clarification.

    Kindly review it. :)

    joachim’s picture

    Status: Needs review » Reviewed & tested by the community

    Perfect, thanks!

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 17: 3283035-17.patch, failed testing. View results

    longwave’s picture

    Status: Needs work » Reviewed & tested by the community

    Random fail, back to RTBC.

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 17: 3283035-17.patch, failed testing. View results

    bruno.bicudo’s picture

    Status: Needs work » Needs review

    Once again, random fail (retested it and passes). Yet, i'l leave it in needs review so that someone else checks it and moves to RTBC again if everything is ok :)

    longwave’s picture

    Status: Needs review » Reviewed & tested by the community

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 17: 3283035-17.patch, failed testing. View results

    longwave’s picture

    Status: Needs work » Reviewed & tested by the community

    Yet another random fail in Quick Edit.

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 17: 3283035-17.patch, failed testing. View results

    longwave’s picture

    Status: Needs work » Reviewed & tested by the community

    Random fail in CKEditor.

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 17: 3283035-17.patch, failed testing. View results

    ravi.shankar’s picture

    Status: Needs work » Reviewed & tested by the community

    Back to RTBC as per the above comments.

    longwave’s picture

    Status: Reviewed & tested by the community » Needs work
    +++ b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php
    @@ -425,7 +426,14 @@ protected function loadFile($file)
    +        try{
    

    Just spotted that we need a space between try and {.

    _pratik_’s picture

    Assigned: Unassigned » _pratik_
    _pratik_’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new1.21 KB
    new577 bytes

    Added spacing around try.
    thanks

    _pratik_’s picture

    Assigned: _pratik_ » Unassigned

    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.

    maacl’s picture

    Status: Needs review » Reviewed & tested by the community

    Typo has been fixed, back to RTBC.

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 32: 3283035-32.patch, failed testing. View results

    spokje’s picture

    Status: Needs work » Reviewed & tested by the community
    xjm’s picture

    Status: Reviewed & tested by the community » Needs review
    Issue tags: +Needs tests

    Nice work. This is a solid bugfix.

    We could provide ExpectedException test coverage for it as well. Is there a reason not to?

    spokje’s picture

    Issue tags: -Needs tests
    StatusFileSize
    new2.39 KB
    new2.4 KB

    Status: Needs review » Needs work

    The last submitted patch, 39: 3283035-39.patch, failed testing. View results

    joachim’s picture

    +++ b/core/tests/Drupal/Tests/Core/DependencyInjection/YamlFileLoaderTest.php
    @@ -169,6 +170,12 @@ public function providerTestExceptions() {
    +      'YAML must be valid' => [<<<YAML
    +   do not:
    +      do this for the love of Foo Bar!
    +YAML,
    

    Heredocs can now be indented with the surrounding code.

    xjm’s picture

    https://www.drupal.org/pift-ci-job/2548777 also looks actually relevant.

    joachim’s picture

    The 'qqq' line in the patch looks like stray test code (in the sense of 'work in progress/experimental', not unit tests) that should have been removed before rolling maybe?

    spokje’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new642 bytes
    new2.03 KB

    The 'qqq' line in the patch looks like stray test code (in the sense of 'work in progress/experimental', not unit tests) that should have been removed before rolling maybe?

    Definitely a case of "Last Patch of The Day"-syndrom.

    Heredocs can now be indented with the surrounding code.

    Tried that locally, but it doesn't seem to work with indentation-sensitive code like YAML.

    smustgrave’s picture

    Status: Needs review » Reviewed & tested by the community

    Ran the test locally for #44 and it fails with

    Failed asserting that exception message 'Unable to parse at line 1 (near "   do not:").' contains 'The file "vfs://drupal/modules/example/example.yml" does not contain valid YAML'.
    

    Tried breaking an existing service but could not but the test shows the issue just fine I believe.

    Looks good!

    catch’s picture

    Status: Reviewed & tested by the community » Needs review
    Issue tags: +Needs followup

    Is this a case where we should be using assertions instead of exceptions? See for example #2454649: Cache Optimization and hardening -- [PP-1] Use assert() instead of exceptions in Cache::merge(Tags|Contexts). Since there are other similar exceptions in the same file, maybe a follow-up?

    smustgrave’s picture

    Status: Needs review » Reviewed & tested by the community
    Issue tags: -Needs followup

    • catch committed e53445ef on 10.1.x
      Issue #3283035 by bruno.bicudo, Spokje, _pratik_, longwave, joachim, xjm...
    catch’s picture

    Status: Reviewed & tested by the community » Fixed

    Committed e53445e and pushed to 10.1.x. Thanks!

    Status: Fixed » Closed (fixed)

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