sipeed/picoclaw · error
write temp file: %w
Error message
write temp file: %w
What it means
Writing the downloaded inbound media bytes to the created temp file failed (media.go:336-339). Writes of up to 20 MiB go to os.TempDir()/picoclaw_media, so ENOSPC (disk/full quota) dominates; EIO and EDQUOT also surface here. The code already closes and unlinks the partial file, so no residue is left.
Source
Thrown at pkg/channels/wecom/media.go:339
resp.Header.Get("Content-Disposition"),
)
ext := filepath.Ext(filename)
if ext == "" {
ext = inferMediaExt(contentType, fallbackExt)
}
mediaDir := filepath.Join(os.TempDir(), "picoclaw_media")
if mkdirErr := os.MkdirAll(mediaDir, 0o700); mkdirErr != nil {
return "", fmt.Errorf("mkdir media dir: %w", mkdirErr)
}
tmpFile, err := os.CreateTemp(mediaDir, msgID+"-*"+ext)
if err != nil {
return "", fmt.Errorf("create temp file: %w", err)
}
tmpPath := tmpFile.Name()
if _, writeErr := tmpFile.Write(data); writeErr != nil {
_ = tmpFile.Close()
_ = os.Remove(tmpPath)
return "", fmt.Errorf("write temp file: %w", writeErr)
}
if closeErr := tmpFile.Close(); closeErr != nil {
_ = os.Remove(tmpPath)
return "", fmt.Errorf("close temp file: %w", closeErr)
}
ref, err := store.Store(tmpPath, media.MediaMeta{
Filename: filename,
ContentType: contentType,
Source: "wecom",
CleanupPolicy: media.CleanupPolicyDeleteOnCleanup,
}, scope)
if err != nil {
_ = os.Remove(tmpPath)
return "", err
}
return ref, nil
}View on GitHub (pinned to 49183d7e8d)
Solutions
- df -h <TMPDIR> - if tmpfs too small, give the media path a real volume or raise the container's memory limit (tmpfs counts against RAM)
- Set TMPDIR to the largest writable volume: ENV TMPDIR=/var/lib/picoclaw/tmp with a mounted PVC/volume
- If quota (EDQUOT): raise the user quota or run the service under a user with headroom
- Guard at the source: reject media near the limit when free space is insufficient
Example fix
# before: media spools to 64MiB tmpfs
resources:
limits: { memory: 128Mi }
# after: spool to a dedicated writable volume
env: [{ name: TMPDIR, value: /var/lib/picoclaw/tmp }]
volumeMounts: [{ name: media, mountPath: /var/lib/picoclaw/tmp }] Defensive patterns
Strategy: validation
Validate before calling
import "golang.org/x/sys/unix"
func tmpHasSpace(needBytes uint64) bool {
var st unix.Statfs_t
if err := unix.Statfs(os.TempDir(), &st); err != nil {
return false
}
return uint64(st.Bavail)*uint64(st.Bsize) > needBytes+64<<20
} Prevention
- monitor free space on the temp volume; alert well above the 20 MiB working set
- prefer a persistent volume over tmpfs for the media spool
- size limits assuming concurrency: N parallel 20 MiB transfers need N x 20 MiB of spool headroom
When it happens
Trigger: tmpfs /tmp smaller than the media (containers default tmpfs to a fraction of RAM); disk quota hit mid-write; NFS/overlayfs write errors; physical disk full.
Common situations: Kubernetes emptyDir/tmpfs sized 64 MiB receiving a 20 MiB video plus other pods' usage; CI runners with tiny scratch disks; shared hosts with per-user quotas.
Related errors
- close destination file %s: %w
- close temp file: %w
- write result: %w
- failed to copy file content: %w
- failed to copy audio data: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/eee28fc5569b67fe.
Report an issue: GitHub.