sipeed/picoclaw · error
failed to create temp file: %w
Error message
failed to create temp file: %w
What it means
Returned when os.CreateTemp(media.TempDir(), "tts-*"+fileExt) fails at pkg/audio/tts/tts.go:137, immediately after the temp dir was created. The pattern is fixed, so failure is environmental: the directory disappeared or is not writable by this process, the process exhausted file descriptors (EMFILE), or the filesystem is full. The deferred cleanup is registered after this point, so no orphan file exists yet.
Source
Thrown at pkg/audio/tts/tts.go:137
return "", fmt.Errorf("failed to create media temp dir: %w", err)
}
fileExt := ".ogg"
contentType := "audio/ogg"
if provider.Name() == "mimo-tts" {
fileExt = ".mp3"
contentType = "audio/mpeg"
}
if metaProvider, ok := stream.(ttsAudioMetaProvider); ok {
if ext, ct := metaProvider.AudioFileMeta(); ext != "" && ct != "" {
fileExt = ext
contentType = ct
}
}
file, err := os.CreateTemp(media.TempDir(), "tts-*"+fileExt)
if err != nil {
return "", fmt.Errorf("failed to create temp file: %w", err)
}
removeTemp := true
defer func() {
if removeTemp {
_ = os.Remove(file.Name())
}
}()
_, err = io.Copy(file, stream)
if err != nil {
_ = file.Close()
return "", fmt.Errorf("failed to write tts audio: %w", err)
}
err = file.Close()
if err != nil {
return "", fmt.Errorf("failed to close tts audio file: %w", err)View on GitHub (pinned to 49183d7e8d)
Solutions
- Inspect the wrapped errno: EMFILE -> raise ulimit -n / fix fd leak; EACCES -> fix dir ownership (chown to service user); ENOSPC -> free disk
- Confirm the directory still exists and is owned by the service user right before retrying: ls -ld <media.TempDir()>
- Disable or exclude the media temp dir from aggressive tmp cleaners, or move it out of /tmp
- Free disk space (df -h) and retry the TTS request
Example fix
# before: service hits EMFILE during parallel TTS ulimit -n 1024 # after: allow headroom for concurrent CreateTemp calls ulimit -n 65536 # or set LimitNOFILE=65536 in the systemd unit
Defensive patterns
Strategy: validation
Validate before calling
// before calling TTS, confirm the dir is usable and fd headroom exists
func canCreateTemp() error {
f, err := os.CreateTemp(media.TempDir(), "probe-*")
if err != nil {
if pe, ok := err.(*fs.PathError); ok && pe.Err == syscall.EMFILE {
return fmt.Errorf("fd limit exhausted: %w", err)
}
return err
}
_ = f.Close()
return os.Remove(f.Name())
} Try / catch
if _, err := os.CreateTemp(media.TempDir(), "tts-*"+ext); err != nil {
var pe *fs.PathError
if errors.As(err, &pe) {
switch {
case errors.Is(pe.Err, syscall.EMFILE): fixFdLimit()
case errors.Is(pe.Err, os.ErrPermission): fixDirOwnership()
case errors.Is(pe.Err, syscall.ENOSPC): freeDisk()
}
}
} Prevention
- Set LimitNOFILE generously (65536) in the service unit
- Keep the temp dir away from tmp cleaners and on the same uid as the service
- Add fd-leak checks (lsof | wc -l) to routine monitoring for long-running bots
When it happens
Trigger: A concurrent tmp-reaper (systemd-tmpfiles, cron cleanup) deleting the just-created directory between MkdirAll and CreateTemp; EMFILE from ulimit -n exhaustion with many parallel TTS calls; EACCES because the 0700 dir was created by a different uid in an earlier run; ENOSPC on a full disk.
Common situations: Long-running bot with fd leaks hitting 'too many open files'; shared /tmp cleaned by tmpwatch while a request is in flight; running the service under a different user than the one that owns the media temp dir; disk full from accumulated TTS audio.
Related errors
- failed to create media temp dir: %w
- failed to close tts audio file: %w
- create output dir: %w
- write result: %w
- failed to save config: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/dfbbf193bf126a5c.
Report an issue: GitHub.