siyuan-note/siyuan · error

send article to liandi failed

Error message

send article to liandi failed [sc=%d]

What it means

The kernel POSTs (or PUTs) the exported document to the Liandi article API. If the HTTP response status is not 200, it logs and returns errors.New("send article to liandi failed [sc=<status>]"). The Liandi endpoint accepted the TCP/HTTP exchange but rejected the request at the HTTP status level.

Solutions

  1. Re-login to Liandi to refresh credentials, then retry the export.
  2. Inspect the reported status code: 401/403 -> auth, 4xx -> payload problem (try a smaller/simpler document), 5xx -> retry later.
  3. Check network connectivity and any proxy between the kernel and Liandi.
  4. Retry after confirming the Liandi service is healthy (the lookup call succeeded earlier).
Defensive patterns

Strategy: retry

Try / catch

if err != nil && strings.Contains(err.Error(), "send article to liandi failed [sc=") {
    // parse status code; on 5xx retry with backoff, on 401/403 re-authenticate
}

Prevention

When it happens

Trigger: Calling Export2Liandi and the create/update article call returns a non-200 status: invalid or expired auth token, payload rejected (413/400), server 5xx, or proxy interference.

Common situations: Token expired mid-session; document too large or containing content Liandi rejects; Liandi server outage; network middleware rewriting the response.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/8801a54fe3b27b2d. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/export.go:508

			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 9f775e8a12)