siyuan-note/siyuan · warning

only local assets/... images are supported

Error message

only local assets/... images are supported

What it means

Returned by PrepareDocumentImage when AssetPathWithoutQuery(assetPath) does not have the prefix "assets/". Only local in-doc assets are eligible for model image input; remote URLs, absolute filesystem paths, and non-assets paths are rejected up front.

Source

Thrown at kernel/model/assets.go:385

	seen := map[string]bool{}
	for _, assetPath := range paths {
		if !strings.HasPrefix(AssetPathWithoutQuery(assetPath), "assets/") || seen[assetPath] {
			continue
		}
		seen[assetPath] = true
		refs = append(refs, ImageArtifactRef{Kind: "image", Path: assetPath, DocumentID: bt.RootID})
	}
	return DocumentImageList{DocumentID: bt.RootID, Images: refs}, nil
}

// PrepareDocumentImage 校验并读取文档实际引用的本地资源图片,供当前模型直接接收图片输入。
func PrepareDocumentImage(documentID, assetPath string) (PreparedDocumentImage, error) {
	assetPath = strings.TrimSpace(assetPath)
	if assetPath == "" {
		return PreparedDocumentImage{}, errors.New("assetPath is required for analyze")
	}
	if !strings.HasPrefix(AssetPathWithoutQuery(assetPath), "assets/") {
		return PreparedDocumentImage{}, errors.New("only local assets/... images are supported")
	}
	bt, err := resolveMultimodalDocument(documentID)
	if err != nil {
		return PreparedDocumentImage{}, err
	}
	if !documentReferencesImage(bt.RootID, assetPath) {
		return PreparedDocumentImage{}, errors.New("assetPath is not an image referenced by the document")
	}
	data, err := ReadAssetBytesInBox(bt.BoxID, assetPath)
	if err != nil {
		return PreparedDocumentImage{}, fmt.Errorf("read image failed: %w", err)
	}
	prepared, err := util.PrepareModelImage(
		data, documentImageMaxBytes, documentImageMaxPixels, documentImageMaxEdge,
	)
	if err != nil {
		return PreparedDocumentImage{}, err
	}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Only pass paths in the form "assets/<filename>" (optionally with "?box=<boxID>" for encrypted notebooks).
  2. For remote images, first download them into the document's assets/ directory via the upload API, then call PrepareDocumentImage.
  3. Use ListDocumentImages to obtain paths guaranteed to be in the accepted form.

Example fix

// before — caller passes a remote URL
prepared, err := model.PrepareDocumentImage(docID, "https://example.com/a.png")

// after — caller downloads into assets/ first, then uses the local path
prepared, err := model.PrepareDocumentImage(docID, "assets/a-20260101000000.png")
Defensive patterns

Strategy: validation

Validate before calling

clean := model.AssetPathWithoutQuery(strings.TrimSpace(assetPath))
if !strings.HasPrefix(clean, "assets/") {
    return fmt.Errorf("asset path must be local assets/... form, got %q", assetPath)
}

Prevention

When it happens

Trigger: Passing a network URL (http/https), an absolute path (/home/x/y.png), a relative path outside assets/ (../foo.png), or a path with a leading slash. The check strips any ?query before testing the prefix, so ?box=... suffixes on encrypted-notebook assets are still allowed — only the prefix is rejected.

Common situations: A user pastes a remote image URL expecting it to be analyzed; a caller passes the full disk path instead of the doc-relative assets/... form; a migrated doc still references an old path scheme.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/218881f0ff94a794. Report an issue: GitHub.