Search code examples
authenticationsystemdtemporary-filesautostart

Program started on boot cannot access /run/user/1000


I have a question regarding an interesting error I'm getting from a Python (3) program being started by systemd. This is all happening on a Raspberry Pi Zero running a fully updated Raspberry Pi OS. It's the brain of a Google AIY Voice Kit v2, though that doesn't seem to be terribly important here.

The systemd service in question runs my Python program, which calls aiy.voice.tts.say("Example text"). However, this returns a FileNotFoundError - the full traceback is:

May 28 21:50:11 voicekit-zero autostart.sh[620]: Traceback (most recent call last):
May 28 21:50:11 voicekit-zero autostart.sh[620]:   File "/home/pi/ready.py", line 27, in <module>
May 28 21:50:11 voicekit-zero autostart.sh[620]:     """, volume=5)
May 28 21:50:11 voicekit-zero autostart.sh[620]:   File "/home/pi/AIY-projects-python/src/aiy/voice/tts.py", line 52, in say
May 28 21:50:11 voicekit-zero autostart.sh[620]:     with tempfile.NamedTemporaryFile(suffix='.wav', dir=RUN_DIR) as f:
May 28 21:50:11 voicekit-zero autostart.sh[620]:   File "/usr/lib/python3.7/tempfile.py", line 686, in NamedTemporaryFile
May 28 21:50:11 voicekit-zero autostart.sh[620]:     (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
May 28 21:50:11 voicekit-zero autostart.sh[620]:   File "/usr/lib/python3.7/tempfile.py", line 397, in _mkstemp_inner
May 28 21:50:11 voicekit-zero autostart.sh[620]:     fd = _os.open(file, flags, 0o600)
May 28 21:50:11 voicekit-zero autostart.sh[620]: FileNotFoundError: [Errno 2] No such file or directory: '/run/user/1000/tmponnl3w02.wav'

It's reasonably clear from this traceback that the TTS script writes a WAV file to a temporary location in /run/user/1000/, then uses it for playback. By that point, however, the file has become inaccessible. My best guess is that the filesystem isn't fully initialized yet. (I'm not certain of this, and I don't have all that much experience with systemd services, so I could definitely be wrong.)

The systemd service file specifies Wants and After for both network-online.target and systemd-timesyncd.service, though of course neither of those are directly related to filesystem readiness. Is there another service I can start after that will ensure the file system is ready for this call? If not, I can just wait a few seconds, though I'd prefer to build a more robust system that should work reliably.

Thanks!


Solution

  • This issue turned out to be easier than I'd anticipated, once I'd filled in some missing details.

    First, this wasn't a problem with Python, or a delay in mounting the filesystem - it centered on the relevant user's (in this case, pi, which has UID 1000) login state at runtime. I discovered that if I logged in via SSH, the error in question disappeared.

    Researching that led me to loginctl enable-linger:

    Enable/disable user lingering for one or more users. If enabled for a specific user, a user manager is spawned for the user at boot and kept around after logouts. This allows users who are not logged in to run long-running services. Takes one or more user names or numeric UIDs as argument. If no argument is specified, enables/disables lingering for the user of the session of the caller.

    Running this command is all that was required to solve the issue.