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 := false

View on GitHub (pinned to 0d3b2f444e)

Solutions

  1. Derive the boundary strictly from the request's Content-Type header (mime.ParseMediaType / multipart.Reader) instead of hardcoding or guessing.
  2. Validate Content-Type starts with 'multipart/' before parsing and reject with 400 otherwise.
  3. Increase read_data capacity if legitimate headers exceed the current buffer size.
  4. 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

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.