siyuan-note/siyuan · error
send article to liandi failed [sc=%d]
Error message
send article to liandi failed [sc=%d]
What it means
Raised inside Export2Liandi when the liandi (community forum) server returns an HTTP status code other than 200 for the POST (new article) or PUT (update article) request to /api/v2/article. The kernel authenticates with the user's symphony cookie (UserToken) and uploads the rendered Markdown plus assets, so a non-200 response means the forum rejected the transport-level request (auth, rate-limit, server fault). The status code is interpolated into the message so the developer can distinguish 401/403/404/429/5xx.
Source
Thrown at kernel/model/export.go:477
SetBody(map[string]any{
"articleTitle": title,
"articleTags": tags,
"articleContent": content})
var resp *req.Response
var sendErr error
if foundArticle {
resp, sendErr = request.Put(apiURL)
} else {
resp, sendErr = request.Post(apiURL)
}
if nil != sendErr {
logging.LogErrorf("send article to liandi failed: %s", sendErr)
return sendErr
}
if 200 != resp.StatusCode {
msg := fmt.Sprintf("send article to liandi failed [sc=%d]", resp.StatusCode)
logging.LogError(msg)
return errors.New(msg)
}
if 0 != result.Code {
msg := fmt.Sprintf("send article to liandi failed [code=%d, msg=%s]", result.Code, result.Msg)
logging.LogError(msg)
util.PushClearMsg(msgId)
return errors.New(result.Msg)
}
if !foundArticle {
articleId = result.Data.(string)
tree, _ = LoadTreeByBlockID(id) // 这里必须重新加载,因为前面导出时已经修改了树结构
tree.Root.SetIALAttr(liandiArticleIdAttrName, articleId)
if err = writeTreeUpsertQueue(tree); err != nil {
return err
}
}
View on GitHub (pinned to 251596fc0d)
Solutions
- Verify the cloud account is logged in and the token is fresh: Settings - About - Cloud account, sign out and back in, then retry.
- Check the kernel log for the exact status code — 401/403 means re-authenticate, 429 means wait and retry, 5xx means the forum is down.
- If behind a proxy, ensure liandi/forum domains are reachable and not intercepted by a captive portal.
- For a stale article-id reference (the doc was deleted on the forum), remove the custom-liandi-articleid IAL attribute from the document root so the next send creates a new article instead of PUT-updating a vanished one.
Example fix
// before — stale articleId forces a PUT against a deleted article
tree.Root.SetIALAttr("custom-liandi-articleid", "")
// after — clears the stale id so Export2Liandi falls back to POST (create new)
// remove the attribute entirely via the doc's attribute panel, or in code:
tree.Root.RemoveIALAttr("custom-liandi-articleid") Defensive patterns
Strategy: validation
Validate before calling
// Validate auth and reachability before calling Export2Liandi
user := Conf.GetUser()
if user == nil || user.UserToken == "" {
return errors.New("cloud account not logged in")
}
// optional: probe the forum endpoint to detect 401/429/5xx early
probe := httpclient.NewCloudRequest30s().SetSuccessResult(gulu.Ret.NewResult())
if resp, err := probe.Get(util.GetCloudAccountServer() + "/api/v2/article"); err != nil || resp.StatusCode >= 400 {
return fmt.Errorf("liandi unreachable [sc=%v]", statusOf(resp))
} Try / catch
// Export2Liandi returns a plain error; inspect its text for [sc=%d] to branch on transport vs business
if err := model.Export2Liandi(id); err != nil {
if strings.Contains(err.Error(), "[sc=") {
// transport-level (non-200) — re-auth or retry with backoff
} else {
// surface the server/business message to the user
}
} Prevention
- Keep the cloud-account token fresh: re-login whenever the forum password changes.
- Before bulk-sending, probe the forum endpoint to confirm 200 reachability.
- Clear stale custom-liandi-articleid attributes when an article was deleted server-side.
- Rate-limit successive Export2Liandi calls to avoid 429.
When it happens
Trigger: Calling the export-to-liandi API endpoint (POST /api/export/export2Liandi with {id}) when the user's cloud account token is expired/invalid (401/403), the forum is rate-limiting (429), the server is down (5xx), or the network proxy mangles the request. Also triggered if the article was deleted server-side between the GET check and the PUT update.
Common situations: The user changed their ld246.com/liuyun.io password but did not re-login in Settings - About - Sync/Cloud, leaving UserToken stale. Corporate firewalls returning a captive-portal 200/302 body that is not valid JSON, or returning 502 for the forum host. Rate-limiting after sending many articles rapidly.
Related errors
- get liandi article info failed [sc=%d]
- The doc in the user guide does not support sharing to the co
- send article to liandi failed: <liandi server response messa
- discover OIDC provider failed: %w
- exchange OIDC authorization code failed: %w
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/8801a54fe3b27b2d.
Report an issue: GitHub.