The trigger for this was an issue we've had at work, where on a D9 site the developers had accidentally removed user.settings.yml completely. The result of this was that we could not log into the site with drush uli - we'd always get a "You have tried to use a reset password link that has expired..." error (otherwise the site was still fully operational). It took us some ridiculous amount of time to figure out what the actual culprit was, so once we did, one of our colleagues has raised https://www.drupal.org/project/drupal/issues/3258523 for Drupal core.

We have similar code in Backdrop:

    // Time out, in seconds, until login URL expires.
    $timeout = config_get('system.core', 'user_password_reset_timeout');
...
      // No time out for first time login.
      if ($account->login && $current - $timestamp > $timeout) {
        backdrop_set_message(t('You have tried to use a reset password link that has expired. Please request a new one using the form below.'), 'error');
        backdrop_goto('user/password');
      }

The difference in Backdrop is that the value for user_password_reset_timeout is saved in system.core.json, so if you try to delete this file, the entire site blows up on you:

So I tried simulating this by removing the user_password_reset_timeout entry from system.core.json instead, and I indeed got myself into the same situation as in Drupal (not being able to log into the site via drush uli, or via password reset links sent through email):

One could argue the following: - It is unlikely that people will go deleting entries from config files manually. - Instead of blindly relying on config_get() returning a proper value for the variable you are using, make sure that a default is specified in-code (do some defensive coding). In other words (using this specific use case as an example - the problem is more broad), this nasty situation could easily be avoided if we did something like this:

$timeout = config_get('system.core', 'user_password_reset_timeout') !== NULL ? config_get('system.core', 'user_password_reset_timeout') : 86400;

These are all valid remarks, but how about if we could be able to do this instead?:

$timeout = config_get('system.core', 'user_password_reset_timeout', 86400);

In other words, get from this: config_get($config_file, $option = NULL) ...to this: config_get($config_file, $option = NULL, $default = NULL)

Other thoughts around this: - We should be more helpful/specific in the error we throw when crucial config files are missing. Listing these files in the error we throw would help people troubleshoot things quicker - separate issue though. - We could introduce a "debugging mode" were warnings would be logged in dblog when trying to read a config file/value that is missing from the file system (don't want to have this on by default - it could possibly flood the dblog) - also separate issue.

GitHub Issue #: 
5453