{"record":{"id":"7256e7c34d2df040","repo":"IceWhaleTech/CasaOS","slug":"not-found-boundary","errorCode":null,"errorMessage":"not found boundary","messagePattern":"not found boundary","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/utils/file/file.go","lineNumber":734,"sourceCode":"\treturn nil, reach_end, nil\n}\n\nfunc ParseFromHead(read_data []byte, read_total int, boundary []byte, stream io.ReadCloser) (map[string]string, []byte, error) {\n\n\tbuf := make([]byte, 1024*8)\n\tfound_boundary := false\n\tboundary_loc := -1\n\n\tfor {\n\t\tread_len, err := stream.Read(buf)\n\t\tif err != nil {\n\t\t\tif err != io.EOF {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tif read_total+read_len > cap(read_data) {\n\t\t\treturn nil, nil, fmt.Errorf(\"not found boundary\")\n\t\t}\n\t\tcopy(read_data[read_total:], buf[:read_len])\n\t\tread_total += read_len\n\t\tif !found_boundary {\n\t\t\tboundary_loc = bytes.LastIndex(read_data[:read_total], boundary)\n\t\t\tif boundary_loc == -1 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfound_boundary = true\n\t\t}\n\t\tstart_loc := boundary_loc + len(boundary)\n\t\tfmt.Println(string(read_data))\n\t\tfile_head_loc := bytes.Index(read_data[start_loc:read_total], []byte(\"\\r\\n\\r\\n\"))\n\t\tif file_head_loc == -1 {\n\t\t\tcontinue\n\t\t}\n\t\tfile_head_loc += start_loc\n\t\tret := false","sourceCodeStart":716,"sourceCodeEnd":752,"githubUrl":"https://github.com/IceWhaleTech/CasaOS/blob/0d3b2f444ec0193193cf03eef6d43c6e35b0183e/pkg/utils/file/file.go#L716-L752","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nboundary := []byte(\"--customboundary\") // guessed\nheadMap, data, err := file.ParseFromHead(readData, 0, boundary, r.Body)\n\n// after\nmediaType, params, err := mime.ParseMediaType(r.Header.Get(\"Content-Type\"))\nif err != nil || !strings.HasPrefix(mediaType, \"multipart/\") {\n\treturn fmt.Errorf(\"expected multipart body\")\n}\nboundary := []byte(\"--\" + params[\"boundary\"])\nheadMap, data, err := file.ParseFromHead(readData, 0, boundary, r.Body)","handlingStrategy":"validation","validationCode":"mediaType, params, err := mime.ParseMediaType(r.Header.Get(\"Content-Type\"))\nif err != nil || !strings.HasPrefix(mediaType, \"multipart/\") || params[\"boundary\"] == \"\" {\n\treturn http.StatusBadRequest, errors.New(\"valid multipart Content-Type with boundary required\")\n}\nboundary := []byte(\"--\" + params[\"boundary\"])","typeGuard":"func hasValidMultipartBoundary(h http.Header) bool {\n\tmt, params, err := mime.ParseMediaType(h.Get(\"Content-Type\"))\n\treturn err == nil && strings.HasPrefix(mt, \"multipart/\") && params[\"boundary\"] != \"\"\n}","tryCatchPattern":"headMap, data, err := file.ParseFromHead(buf, 0, boundary, r.Body)\nif err != nil {\n\tif strings.Contains(err.Error(), \"not found boundary\") {\n\t\treturn http.StatusBadRequest, errors.New(\"multipart boundary mismatch\") // permanent, no retry\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["multipart","parsing","http","upload"],"backgroundTag":null,"analyzedSha":"0d3b2f444ec0193193cf03eef6d43c6e35b0183e","analyzedAt":"2026-08-15T13:27:57.821Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}