Do not rely on the the HOME variable being available in system scripts

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the unix category.

Last Updated: 2022-05-26

I had a deploy that failed.

When I looked at the logs, I saw an odd error from the server process started by the system as a daemon via service (FYI: service is a wrapper for either init.d or systemctl)

ERROR -- : couldn't find login name -- expanding `~' (ArgumentError)

The backtrace indicated this was caused by the code trying to require a Ruby REPL package called pry. The offending bit was this code within the initialization of the library:

HOME_RC_FILE =
  if File.exist?(File.expand_path('~/.pryrc'))
    '~/.pryrc'
  end

The error seems to suggest the reference to ~ in the file path was the issue!

To check this out, I tried this code manually from a Ruby terminal, and it was completely fine.

Behind the scenes, ~ depends on $HOME, which was set in this case. Eventually I found the problem: This script was run from service, with an init.d script.

With the settings I had (defaults, I think?), this strips all environment variables other than TERM, PATH and LANG. This is done in order to create a stable environment. So be aware it breaks other environmental dependencies, like references to the HOME directory.

Lessons

  1. Even a require line can break code (due to setup initialization done by the library and the environmental expectations it has)
  2. Not even the $HOME variable is guaranteed when run with service. So don't rely on ENV variables you don't set here.

References