Billionmail/BillionMail · error
create output dir: %w
Error message
create output dir: %w
What it means
TextToSpeech first ensures cfg.OutputDir exists via os.MkdirAll(dir, 0755) before writing any audio. If the directory cannot be created (permission denied, path is an existing file, read-only filesystem, invalid path), the OS error is wrapped as 'create output dir'. It is a local filesystem failure, not a Cartesia problem.
Source
Thrown at core/internal/service/video_gen/voice.go:170
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("cartesia clone API error %d: %s", resp.StatusCode, string(body))
}
var result VoiceCloneResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decode clone response: %w", err)
}
return &result, nil
}
// TextToSpeech generates audio from text using a Cartesia voice.
// Returns the path to the output WAV file.
func TextToSpeech(ctx context.Context, cfg VoiceConfig, voiceID, transcript, filename string) (string, error) {
if err := os.MkdirAll(cfg.OutputDir, 0755); err != nil {
return "", fmt.Errorf("create output dir: %w", err)
}
req := TTSRequest{
VoiceID: voiceID,
Transcript: transcript,
ModelID: "sonic-2",
OutputFormat: DefaultTTSOutputFormat(),
Language: "en",
}
httpReq, err := BuildTTSRequest(cfg, req)
if err != nil {
return "", err
}
httpReq = httpReq.WithContext(ctx)
resp, err := cfg.doHTTP(httpReq)
if err != nil {View on GitHub (pinned to fc36c76c05)
Solutions
- Check OutputDir is writable by the process user: ls -ld and touch a test file.
- Verify OutputDir is not an existing regular file; fix the config value.
- Ensure the container/volume is mounted read-write and has free space.
- Create the directory ahead of time with correct ownership (mkdir -p + chown).
- Pre-validate OutputDir in DefaultVoiceConfig / startup config checks.
Example fix
// before
if err := os.MkdirAll(cfg.OutputDir, 0755); err != nil {
return "", fmt.Errorf("create output dir: %w", err)
}
// after
if info, err := os.Stat(cfg.OutputDir); err == nil && !info.IsDir() {
return "", fmt.Errorf("output dir %s is a file", cfg.OutputDir)
}
if err := os.MkdirAll(cfg.OutputDir, 0o755); err != nil {
return "", fmt.Errorf("create output dir %s: %w", cfg.OutputDir, err)
} Defensive patterns
Strategy: validation
Validate before calling
func ensureWritableDir(dir string) error {
info, err := os.Stat(dir)
if err == nil && !info.IsDir() {
return fmt.Errorf("%s exists and is not a directory", dir)
}
if err := os.MkdirAll(dir, 0o755); err != nil {
return err
}
probe := filepath.Join(dir, ".write-test")
if err := os.WriteFile(probe, nil, 0o644); err != nil {
return err
}
return os.Remove(probe)
}
// call before TextToSpeech:
if err := ensureWritableDir(cfg.OutputDir); err != nil {
return fmt.Errorf("output dir unusable: %w", err)
} Try / catch
path, err := video_gen.TextToSpeech(ctx, cfg, voiceID, transcript, filename)
if err != nil {
if strings.Contains(err.Error(), "create output dir") || strings.Contains(err.Error(), "create output file") {
log.Printf("filesystem problem with %s: %v", cfg.OutputDir, err)
// fix config/permissions, then retry
}
return err
} Prevention
- Default OutputDir to a path writable by the service user (e.g. /var/lib/app/audio)
- Mount container volumes read-write with correct ownership
- Validate OutputDir at startup, not at first TTS call
- Monitor free disk space on the audio volume
When it happens
Trigger: cfg.OutputDir points inside a directory the process cannot write (e.g. /root/... when running unprivileged), OutputDir path exists as a regular file, read-only container filesystem, or a path with invalid characters.
Common situations: Docker containers mounting volumes read-only, running service as non-root user while OutputDir defaults to a root-owned path, typo'd OutputDir config, disk-full or SELinux/AppArmor denial.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- error reading project configuration file: %v
- error writing project configuration file: %v
- error writing knowledge base file: %v
- error creating company profile file: %v
- error reading company profile file: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/3c938277e6e9c9ab.
Report an issue: GitHub.