{"record":{"id":"a1a0ac43714cc6f7","repo":"siyuan-note/siyuan","slug":"write-file-failed-s","errorCode":null,"errorMessage":"write file failed: %s","messagePattern":"write file failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/httprequest.go","lineNumber":121,"sourceCode":"\tif resp.ContentLength > maxReadBytes {\n\t\treturn statusCode, contentType, \"\", errors.New(\"response too large\")\n\t}\n\n\trespBody, rerr := io.ReadAll(io.LimitReader(resp.Body, maxReadBytes))\n\tif rerr != nil {\n\t\treturn statusCode, contentType, \"\", errors.New(\"read body failed: \" + rerr.Error())\n\t}\n\n\t// 二进制响应落盘，返回文件路径，供智能体按需进一步处理。\n\tif !isTextContentType(contentType) {\n\t\timportDir := filepath.Join(TempDir, \"import\")\n\t\tif merr := os.MkdirAll(importDir, 0755); merr != nil {\n\t\t\treturn statusCode, contentType, \"\", errors.New(\"create import dir failed: \" + merr.Error())\n\t\t}\n\t\tfilename := extractFilename(rawURL, contentType)\n\t\tfilePath := filepath.Join(importDir, filename)\n\t\tif werr := os.WriteFile(filePath, respBody, 0644); werr != nil {\n\t\t\treturn statusCode, contentType, \"\", errors.New(\"write file failed: \" + werr.Error())\n\t\t}\n\t\treturn statusCode, contentType, fmt.Sprintf(\"Saved to: %s (%d bytes)\", filePath, len(respBody)), nil\n\t}\n\n\treturn statusCode, contentType, truncateRunes(string(respBody), maxHTTPRequestChars), nil\n}\n\n// sendByMethod 按 method 分发请求，统一走 NewBrowserRequest 返回的 *req.Request。\nfunc sendByMethod(request *req.Request, method, rawURL string) (*req.Response, error) {\n\tswitch method {\n\tcase \"GET\", \"\":\n\t\treturn request.Get(rawURL)\n\tcase \"POST\":\n\t\treturn request.Post(rawURL)\n\tcase \"PUT\":\n\t\treturn request.Put(rawURL)\n\tcase \"DELETE\":\n\t\treturn request.Delete(rawURL)","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/httprequest.go#L103-L139","documentation":"Raised by HTTPRequest after the import directory is created but os.WriteFile cannot persist the binary response body to TempDir/import/<filename>. The %s is the wrapped OS write error. The filename comes from extractFilename(rawURL, contentType), which derives it from the URL path or a random string plus a content-type extension.","triggerScenarios":"A non-text response is written with os.WriteFile(filePath, respBody, 0644) and the write fails. Causes: destination volume is full, the resolved filename contains characters the filesystem rejects, the path is too long, or the directory was removed between MkdirAll and WriteFile (TOCTOU).","commonSituations":"Disk full when the agent downloads a large binary (up to maxHTTPRequestFileBytes = 10 MiB); a URL whose final path segment contains illegal filename characters on the host OS; antivirus or sync software locking the import directory; concurrent http_request calls racing on the same filename.","solutions":["Check free space on the TempDir volume (df) and free space or raise maxHTTPRequestFileBytes awareness before large downloads.","Inspect the resolved filename in the error path for illegal characters and sanitize the URL or set a Content-Disposition-friendly name upstream.","Ensure no other process (sync client, AV) holds an exclusive lock on TempDir/import.","Retry the http_request; transient write failures (lock, momentary full disk) often clear."],"exampleFix":"// before: large binary write fails on full disk\n// after: preflight free space before calling HTTPRequest for big assets\nvar stat syscall.Statfs_t\nif err := syscall.Statfs(util.TempDir, &stat); err == nil {\n    free := stat.Bavail * uint64(stat.Bsize)\n    if free < uint64(maxHTTPRequestFileBytes) {\n        return errors.New(\"insufficient disk space for binary download\")\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight free-space check for binary downloads.\nvar stat syscall.Statfs_t\nif err := syscall.Statfs(filepath.Join(util.TempDir, \"import\"), &stat); err == nil {\n    free := stat.Bavail * uint64(stat.Bsize)\n    if free < 10*1024*1024 {\n        return errors.New(\"insufficient disk space for binary download\")\n    }\n}","typeGuard":null,"tryCatchPattern":"statusCode, contentType, text, err := util.HTTPRequest(method, rawURL, headers, body)\nif err != nil && strings.Contains(err.Error(), \"write file failed\") {\n    // transient: disk full / lock; surface to caller, suggest retry after cleanup\n    return fmt.Errorf(\"binary save failed (free space / lock?): %w\", err)\n}","preventionTips":["Monitor free space on the TempDir volume.","Sanitize URL path segments before they become filenames.","Avoid concurrent http_request calls that resolve to the same filename."],"tags":["filesystem","http","mcp","agent-tool","disk-full"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}