{"record":{"id":"dfbbf193bf126a5c","repo":"sipeed/picoclaw","slug":"failed-to-create-temp-file-w","errorCode":null,"errorMessage":"failed to create temp file: %w","messagePattern":"failed to create temp file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/audio/tts/tts.go","lineNumber":137,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"failed to create media temp dir: %w\", err)\n\t}\n\n\tfileExt := \".ogg\"\n\tcontentType := \"audio/ogg\"\n\tif provider.Name() == \"mimo-tts\" {\n\t\tfileExt = \".mp3\"\n\t\tcontentType = \"audio/mpeg\"\n\t}\n\tif metaProvider, ok := stream.(ttsAudioMetaProvider); ok {\n\t\tif ext, ct := metaProvider.AudioFileMeta(); ext != \"\" && ct != \"\" {\n\t\t\tfileExt = ext\n\t\t\tcontentType = ct\n\t\t}\n\t}\n\n\tfile, err := os.CreateTemp(media.TempDir(), \"tts-*\"+fileExt)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create temp file: %w\", err)\n\t}\n\n\tremoveTemp := true\n\tdefer func() {\n\t\tif removeTemp {\n\t\t\t_ = os.Remove(file.Name())\n\t\t}\n\t}()\n\n\t_, err = io.Copy(file, stream)\n\tif err != nil {\n\t\t_ = file.Close()\n\t\treturn \"\", fmt.Errorf(\"failed to write tts audio: %w\", err)\n\t}\n\n\terr = file.Close()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to close tts audio file: %w\", err)","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/audio/tts/tts.go#L119-L155","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: service hits EMFILE during parallel TTS\nulimit -n 1024\n\n# after: allow headroom for concurrent CreateTemp calls\nulimit -n 65536  # or set LimitNOFILE=65536 in the systemd unit","handlingStrategy":"validation","validationCode":"// before calling TTS, confirm the dir is usable and fd headroom exists\nfunc canCreateTemp() error {\n    f, err := os.CreateTemp(media.TempDir(), \"probe-*\")\n    if err != nil {\n        if pe, ok := err.(*fs.PathError); ok && pe.Err == syscall.EMFILE {\n            return fmt.Errorf(\"fd limit exhausted: %w\", err)\n        }\n        return err\n    }\n    _ = f.Close()\n    return os.Remove(f.Name())\n}","typeGuard":null,"tryCatchPattern":"if _, err := os.CreateTemp(media.TempDir(), \"tts-*\"+ext); err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) {\n        switch {\n        case errors.Is(pe.Err, syscall.EMFILE): fixFdLimit()\n        case errors.Is(pe.Err, os.ErrPermission): fixDirOwnership()\n        case errors.Is(pe.Err, syscall.ENOSPC): freeDisk()\n        }\n    }\n}","preventionTips":["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"],"tags":["go","filesystem","resource-limits","tts","temp-files"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}