siyuan-note/siyuan · error

not found executable pandoc

Error message

not found executable pandoc

What it means

ConvertPandoc and Pandoc refuse to run when GetPandocRuntime().BinPath is empty or the process runs in a non-standard container (ContainerStd != Container, e.g. Docker, where InitPandoc disables the runtime by design). BinPath is resolved once at startup from the bundled <WorkingDir>/pandoc/bin binary or from a custom path validated by IsValidPandocBin; empty means no usable pandoc executable was found.

Source

Thrown at kernel/util/pandoc.go:33

// along with this program.  If not, see <https://www.gnu.org/licenses/>.

package util

import (
	"bytes"
	"errors"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	"github.com/88250/gulu"
	"github.com/siyuan-note/logging"
)

var ErrPandocNotFound = errors.New("not found executable pandoc")

func ConvertPandoc(dir string, args ...string) (path string, err error) {
	pandocBinPath := GetPandocRuntime().BinPath
	if "" == pandocBinPath || ContainerStd != Container {
		err = ErrPandocNotFound
		return
	}

	pandoc := exec.Command(pandocBinPath, args...)
	gulu.CmdAttr(pandoc)
	path = filepath.Join("temp", "convert", "pandoc", dir)
	absPath := filepath.Join(WorkspaceDir, path)
	if err = os.MkdirAll(absPath, 0755); err != nil {
		logging.LogErrorf("mkdir [%s] failed: [%s]", absPath, err)
		return
	}
	pandoc.Dir = absPath
	output, err := pandoc.CombinedOutput()

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Provide a working pandoc: install the bundled runtime under <WorkingDir>/pandoc/bin, or set a custom pandoc binary path in settings that passes IsValidPandocBin (a real binary whose --version starts with 'pandoc').
  2. Restart or re-run InitPandoc after changing the path — the runtime is resolved at init time, not per call.
  3. Verify with pandoc --version as the same user account that runs SiYuan to rule out permission issues.
  4. In Docker, pandoc conversion is intentionally unavailable (ContainerStd != Container) — use a non-containerized setup or avoid pandoc-dependent flows.

Example fix

// before: no pandoc installed, custom path empty
util.InitPandoc("")
path, err := util.ConvertPandoc(dir, args...) // -> ErrPandocNotFound

// after: configure a valid binary (or ship <workdir>/pandoc/bin/pandoc)
util.InitPandoc("/usr/local/bin/pandoc")
path, err := util.ConvertPandoc(dir, args...)
Defensive patterns

Strategy: validation

Validate before calling

if util.GetPandocRuntime().BinPath == "" {
	return util.ErrPandocNotFound // or prompt the user to install/configure pandoc
}
path, err := util.ConvertPandoc(dir, args...)

Try / catch

Compare with errors.Is(err, util.ErrPandocNotFound) and degrade gracefully — skip the conversion and tell the user to install pandoc, rather than retrying; it is a deterministic environment problem.

Prevention

When it happens

Trigger: Triggering any pandoc-backed conversion (Word/Docx import, export to docx, pandoc-format conversion) on an installation where the bundled pandoc binary is missing, the configured custom pandoc path fails IsValidPandocBin (not a real Mach-O/ELF/PE binary, or its --version output does not start with 'pandoc'), or inside a Docker container where pandoc is intentionally disabled.

Common situations: Fresh or copied installations missing the pandoc folder; a custom path pointing to a script, symlink to nowhere, or wrong binary; permission problems executing pandoc; Docker deployments.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/369cd0f6dee1f1fe. Report an issue: GitHub.