Tencent/WeKnora · error
failed to write file: %w
Error message
failed to write file: %w
What it means
SaveBytes wraps any error from os.WriteFile when writing the byte payload to the uniquely named file under baseDir/<tenantID>/exports as "failed to write file: %w". The directory was already created successfully, so this error is specifically about creating/writing the final file, with the original OS error preserved for unwrapping.
Source
Thrown at internal/application/service/file/local.go:243
}
// Create storage directory with tenant ID
dir := filepath.Join(s.baseDir, fmt.Sprintf("%d", tenantID), "exports")
if err := os.MkdirAll(dir, 0o755); err != nil {
logger.Errorf(ctx, "Failed to create directory: %v", err)
return "", fmt.Errorf("failed to create directory: %w", err)
}
// Generate unique filename using timestamp
ext := filepath.Ext(safeName)
baseName := safeName[:len(safeName)-len(ext)]
uniqueFileName := fmt.Sprintf("%s_%d%s", baseName, time.Now().UnixNano(), ext)
filePath := filepath.Join(dir, uniqueFileName)
// Write data to file
if err := os.WriteFile(filePath, data, 0o644); err != nil {
logger.Errorf(ctx, "Failed to write file: %v", err)
return "", fmt.Errorf("failed to write file: %w", err)
}
logger.Infof(ctx, "Bytes data saved successfully: %s", filePath)
relPath, _ := filepath.Rel(s.baseDir, filePath)
return localScheme + filepath.ToSlash(relPath), nil
}
// GetFileURL returns a download URL for the file.
// When externalURL is configured, returns a presigned HTTP URL suitable for external access.
// Otherwise returns the local://... path for backward compatibility.
func (s *localFileService) GetFileURL(ctx context.Context, filePath string) (string, error) {
// Normalize to provider:// format.
normalized := filePath
if !strings.HasPrefix(filePath, localScheme) {
relPath, err := filepath.Rel(s.baseDir, filePath)
if err != nil {
normalized = filePath
} else {View on GitHub (pinned to 988cbb0330)
Solutions
- Unwrap with errors.Is(err, fs.ErrPermission) / syscall.ENOSPC and address accordingly: fix directory permissions or free disk/quota space
- Confirm the volume backing baseDir is mounted read-write and has enough free space for the payload size (df -h)
- Check for background cleanup/rsync jobs racing on the exports directory and exclude in-flight writes
- If SELinux denies writes, relabel the directory (restorecon) or adjust the container security policy
- Retry SaveBytes with backoff for transient ENOSPC/EIO conditions
Example fix
// before
path, err := svc.SaveBytes(ctx, data, tenantID, "report.csv", false)
if err != nil {
log.Fatal(err) // opaque
}
// after
path, err := svc.SaveBytes(ctx, data, tenantID, "report.csv", false)
if err != nil {
if errors.Is(err, syscall.ENOSPC) {
// free space / alert ops, then retry
} else if errors.Is(err, fs.ErrPermission) {
// fix permissions on baseDir
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
func ensureFreeSpace(dir string, need uint64) error {
var st syscall.Statfs_t
if err := syscall.Statfs(dir, &st); err != nil {
return err
}
avail := st.Bavail * uint64(st.Bsize)
if avail < need*2 { // headroom for the payload
return fmt.Errorf("insufficient space in %s: %d < %d", dir, avail, need*2)
}
return nil
}
// call before SaveBytes: ensureFreeSpace(exportsDir, uint64(len(data))) Try / catch
path, err := svc.SaveBytes(ctx, data, tenantID, name, false)
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && errors.Is(perr.Err, syscall.ENOSPC) {
// alert / free space, then retry with backoff
}
return fmt.Errorf("save failed: %w", err)
} Prevention
- Check available disk space (or quota) before writing large payloads
- Keep baseDir on a volume with monitoring and low-disk alerts
- Avoid aggressive cleanup jobs that could remove the exports dir between MkdirAll and WriteFile
- Set sensible retention policies so the export volume does not fill up
When it happens
Trigger: os.WriteFile(filePath, data, 0o644) fails: path component vanished between MkdirAll and WriteFile, permission denied on the directory, disk full so the write is short, file name too long after the timestamp suffix, or a symlink/race replaces the target path.
Common situations: Disk quota exceeded for the tenant volume; read-only mount discovered only at write time; baseDir on tmpfs that ran out of space for large uploads; concurrent cleanup job deleting the exports dir mid-write; SELinux/AppArmor denying write to the path.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- failed to create destination file: %w
- failed to copy file content: %w
- failed to open source file: %w
- save: %w
- failed to read script for validation: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/5dceaf4cb0061790.
Report an issue: GitHub.