-
Notifications
You must be signed in to change notification settings - Fork 24
Description
it is a simple typo in logic but its impact is catastrophic for the usability of the SDK. it renders a major capability of the library completely non functional. The addFile() function in all service clients contains a critical bug where the file handle is closed immediately after opening, and then the code attempts to read from the already closed file using io.Copy(). This causes all multipart file uploads to fail with the error:
read /path/to/file: file already closed
The bug is located in services/*/client.go (lines 499-516) and affects all 37+ service clients in the SDK since the code is auto generated.
The Buggy Code
func addFile(w *multipart.Writer, fieldName, path string) error {
file, err := os.Open(filepath.Clean(path))
if err != nil {
return err
}
err = file.Close() // bug: File is closed here!
if err != nil {
return err
}
part, err := w.CreateFormFile(fieldName, filepath.Base(path))
if err != nil {
return err
}
_, err = io.Copy(part, file) // bug: trying to read from closed file!
return err
}Steps to reproduce
package main
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"os"
"path/filepath"
)
// This is the EXACT code from services/iaas/client.go (lines 499-516)
func addFile(w *multipart.Writer, fieldName, path string) error {
file, err := os.Open(filepath.Clean(path))
if err != nil {
return err
}
err = file.Close() // bug: closed too early!
if err != nil {
return err
}
part, err := w.CreateFormFile(fieldName, filepath.Base(path))
if err != nil {
return err
}
_, err = io.Copy(part, file) // fails: file already closed
return err
}
func main() {
// Step 1: create a test file with content
testFile, _ := os.CreateTemp("", "upload_test_*.txt")
testFile.WriteString("This content should be uploaded to the API!")
testFile.Close()
defer os.Remove(testFile.Name())
// Step 2: try to add the file to a multipart form (simulating SDK file upload)
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
err := addFile(writer, "file", testFile.Name())
writer.Close()
// Step 3: observe the error
if err != nil {
fmt.Printf("ERROR: %v\n", err)
} else {
fmt.Println("Success (unexpected)")
}
}- run the code above with
go run main.go - observe the error output
Actual behavior
The SDK returns an error when trying to upload any file:
ERROR: read /tmp/upload_test_1234567890.txt: file already closed
The file upload operation fails completely. no data is sent to the API.
Test output from POC:
=== RUN TestRealSDK_AddFile_Bug_FileClosedBeforeRead
bug CONFIRMED: Real SDK addFile() returned error!
Error: read /tmp/real_sdk_addfile_test_3259669529.txt: file already closed
Confirmed: 'file already closed' error!
--- PASS: TestRealSDK_AddFile_Bug_FileClosedBeforeRead
Expected behavior
The addFile() function should:
- Open the file
- Read its contents using
io.Copy() - Then close the file after reading is complete
The file should remain open until after io.Copy() finishes reading. The correct implementation should use defer file.Close():
func addFile(w *multipart.Writer, fieldName, path string) error {
file, err := os.Open(filepath.Clean(path))
if err != nil {
return err
}
defer file.Close() // close after io.Copy completes
part, err := w.CreateFormFile(fieldName, filepath.Base(path))
if err != nil {
return err
}
_, err = io.Copy(part, file) // file is still open here
return err
}Environment
-
OS: Linux (Ubuntu 22.04)
-
Go version (see
go version):1.25.5 -
Version of the STACKIT Go SDK:
$ cat go.mod | grep "stackit"
module github.com/stackitcloud/stackit-sdk-go/services/iaas
github.com/stackitcloud/stackit-sdk-go/core v0.20.1
github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.18.2
Additional information
affected Services
This bug affects ALL service clients (37+ files) because the code is generated from the same template:
Root Cause
I think the bug appears to be in the OpenAPI Generator template used to generate the SDK client code. fixing the template would fix the bug across all services when the SDK is regenerated.
I'm happy to help test a fix or sumbit a PR . Thank you!