Tencent/WeKnora · error
failed to open file: %w
Error message
failed to open file: %w
What it means
SaveFile opens the uploaded multipart file (file.Open() on a *multipart.FileHeader) before uploading to OSS; this error wraps any failure from that open operation with 'failed to open file: %w'. It means the multipart part backing the upload could not be read — typically because the underlying temp file or request body is no longer available.
Source
Thrown at internal/application/service/file/oss.go:174
if err != nil {
return fmt.Errorf("failed to check OSS bucket: %w", err)
}
if !exists {
return fmt.Errorf("bucket %q does not exist", s.bucketName)
}
return nil
}
// SaveFile saves a file to OSS using the Uploader manager for large files.
func (s *ossFileService) SaveFile(ctx context.Context,
file *multipart.FileHeader, tenantID uint64, knowledgeID string,
) (string, error) {
ext := filepath.Ext(file.Filename)
objectName := fmt.Sprintf("%s%d/%s/%s%s", s.pathPrefix, tenantID, knowledgeID, uuid.New().String(), ext)
src, err := file.Open()
if err != nil {
return "", fmt.Errorf("failed to open file: %w", err)
}
defer src.Close()
contentType := file.Header.Get("Content-Type")
if contentType == "" {
contentType = utils.GetContentTypeByExt(ext)
}
// Use Uploader for files > 10MB (auto multipart with concurrent uploads)
const multipartThreshold = 10 * 1024 * 1024
if file.Size > multipartThreshold {
uploader := s.client.NewUploader(func(uo *oss.UploaderOptions) {
uo.PartSize = 10 * 1024 * 1024 // 10MB per part
uo.ParallelNum = 3 // 3 concurrent uploads
})
_, err = uploader.UploadFrom(ctx,
&oss.PutObjectRequest{View on GitHub (pinned to 988cbb0330)
Solutions
- Upload synchronously inside the request handler before returning — never defer SaveFile to a goroutine or background job using the same FileHeader
- Verify the server temp dir exists, is writable, and has free space (check TMPDIR, disk usage, permissions)
- Read the multipart form fully and check r.ParseMultipartForm errors before accessing the FileHeader
- If async processing is needed, copy the file contents into a buffer/temp file you own within the handler, then pass that
Example fix
// before (broken async)
func handler(w http.ResponseWriter, r *http.Request) {
f, _, _ := r.FormFile("file")
go svc.SaveFile(ctx, tenantID, kid, f) // temp file gone by the time goroutine runs
}
// after
func handler(w http.ResponseWriter, r *http.Request) {
fh, _, err := r.FormFile("file")
if err != nil { http.Error(w, err.Error(), 400); return }
defer fh.Close()
if _, err := svc.SaveFile(r.Context(), tenantID, kid, fh); err != nil {
http.Error(w, err.Error(), 500); return
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before SaveFile, verify the FileHeader is readable in the same request lifecycle
f, err := fh.Open()
if err != nil { return fmt.Errorf("upload unreadable: %w", err) }
f.Close()
// Also check temp space
if st, err := os.Stat(os.TempDir()); err != nil || !st.IsDir() { return errors.New("temp dir unavailable") } Try / catch
objectPath, err := svc.SaveFile(ctx, tenantID, knowledgeID, fileHeader)
if err != nil {
var pe *fs.PathError
if errors.As(err, &pe) {
return fmt.Errorf("upload temp file inaccessible (%s): %w", pe.Path, err)
}
return fmt.Errorf("save failed: %w", err)
} Prevention
- Always call SaveFile synchronously within the HTTP request handler; copy to your own buffer first if async processing is required
- Monitor server temp-dir writability and free disk space
- Handle client-disconnect and ParseMultipartForm errors before touching the FileHeader
- Never reuse multipart.FileHeader objects across requests or after the request context ends
When it happens
Trigger: Calling SaveFile with a *multipart.FileHeader whose underlying temp file was removed, whose request body was already consumed/closed, or a corrupted multipart form; also possible when the FileHeader was retained past the HTTP request lifetime (Go cleans request temp files when the handler returns).
Common situations: Storing multipart.FileHeader in a queue/cache and calling SaveFile after the HTTP request has ended; server temp directory (TMPDIR) permissions or disk-full preventing temp file writes; client disconnected mid-upload; middleware closing the request body early.
Related errors
- failed to open file: %w
- failed to upload file to OSS (multipart): %w
- write file content: %w
- write file content: %w
- failed to save file: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/bc39ad698b672881.
Report an issue: GitHub.