IceWhaleTech/CasaOS · error
not found boundary
Error message
not found boundary
What it means
While scanning a multipart stream for the boundary delimiter in ParseFromHead, the accumulated bytes exceeded the capacity of the read buffer before any boundary was found. The parser gives up with 'not found boundary' because a valid multipart body must present the boundary within the buffer window.
Source
Thrown at pkg/utils/file/file.go:734
return nil, reach_end, nil
}
func ParseFromHead(read_data []byte, read_total int, boundary []byte, stream io.ReadCloser) (map[string]string, []byte, error) {
buf := make([]byte, 1024*8)
found_boundary := false
boundary_loc := -1
for {
read_len, err := stream.Read(buf)
if err != nil {
if err != io.EOF {
return nil, nil, err
}
break
}
if read_total+read_len > cap(read_data) {
return nil, nil, fmt.Errorf("not found boundary")
}
copy(read_data[read_total:], buf[:read_len])
read_total += read_len
if !found_boundary {
boundary_loc = bytes.LastIndex(read_data[:read_total], boundary)
if boundary_loc == -1 {
continue
}
found_boundary = true
}
start_loc := boundary_loc + len(boundary)
fmt.Println(string(read_data))
file_head_loc := bytes.Index(read_data[start_loc:read_total], []byte("\r\n\r\n"))
if file_head_loc == -1 {
continue
}
file_head_loc += start_loc
ret := falseView on GitHub (pinned to 0d3b2f444e)
Solutions
- Derive the boundary strictly from the request's Content-Type header (mime.ParseMediaType / multipart.Reader) instead of hardcoding or guessing.
- Validate Content-Type starts with 'multipart/' before parsing and reject with 400 otherwise.
- Increase read_data capacity if legitimate headers exceed the current buffer size.
- Prefer Go's standard mime/multipart package for correctness.
Example fix
// before
boundary := []byte("--customboundary") // guessed
headMap, data, err := file.ParseFromHead(readData, 0, boundary, r.Body)
// after
mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil || !strings.HasPrefix(mediaType, "multipart/") {
return fmt.Errorf("expected multipart body")
}
boundary := []byte("--" + params["boundary"])
headMap, data, err := file.ParseFromHead(readData, 0, boundary, r.Body) Defensive patterns
Strategy: validation
Validate before calling
mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil || !strings.HasPrefix(mediaType, "multipart/") || params["boundary"] == "" {
return http.StatusBadRequest, errors.New("valid multipart Content-Type with boundary required")
}
boundary := []byte("--" + params["boundary"]) Type guard
func hasValidMultipartBoundary(h http.Header) bool {
mt, params, err := mime.ParseMediaType(h.Get("Content-Type"))
return err == nil && strings.HasPrefix(mt, "multipart/") && params["boundary"] != ""
} Try / catch
headMap, data, err := file.ParseFromHead(buf, 0, boundary, r.Body)
if err != nil {
if strings.Contains(err.Error(), "not found boundary") {
return http.StatusBadRequest, errors.New("multipart boundary mismatch") // permanent, no retry
}
return err
} Prevention
- Always take the boundary from the Content-Type header, never hardcode it
- Reject non-multipart content types before parsing
- Size multipart header buffers to your max header budget
When it happens
Trigger: Parsing a request body whose declared boundary never appears in the data — wrong boundary string (e.g. missing '--' prefix or not taken from the Content-Type header), a non-multipart body fed to the parser, or headers larger than the buffer capacity.
Common situations: Content-Type boundary parameter mismatched with the actual body; proxies/clients rewriting or stripping multipart headers; very large multipart headers exceeding the buffer; body encoded/encrypted so the delimiter bytes never occur.
Related errors
AI-assisted analysis of IceWhaleTech/CasaOS@0d3b2f444e (2026-08-15).
Data as JSON: /api/errors/7256e7c34d2df040.
Report an issue: GitHub.