siyuan-note/siyuan · error

skill source is not a regular file

Error message

skill source is not a regular file

What it means

readManagedSkillSource opens a skill file and Stats it before reading; this error means the opened file descriptor does not refer to a regular file (e.g. a FIFO, device or special file). The library only returns UTF-8 text content to the editor, so non-regular sources are rejected before any read occurs.

Solutions

  1. Replace the special file at the path with a regular text file containing the skill content
  2. Identify which process created the special file and stop it from writing into data/storage/ai/agent/skills
  3. Re-create the file via the skill management API (action "write") instead of manually

Example fix

// before (accidentally a FIFO)
mkfifo data/storage/ai/agent/skills/my-skill/SKILL.md
// after
printf -- '---\nname: my-skill\ndescription: x\n---\n' > data/storage/ai/agent/skills/my-skill/SKILL.md
Defensive patterns

Strategy: type-guard

Validate before calling

info, err := os.Stat(filepath.Join(dataDir, "storage/ai/agent/skills", p))
if err == nil && !info.Mode().IsRegular() {
  // replace with a regular file before calling read
}

Type guard

func isRegularFile(info os.FileInfo) bool { return info.Mode().IsRegular() }

Try / catch

if err := ManageSkillFiles(req); err != nil && strings.Contains(err.Error(), "not a regular file") {
  // recreate the path as a regular text file
}

Prevention

When it happens

Trigger: ManageSkillFiles read (or write/move/remove pre-checks) on a path that passed validateManagedSkillPath but whose root.Open(...).Stat() reports a non-regular mode — typically a FIFO, /dev-like node or similar placed at a skill file path; called during list to compute Editable, and before move/remove of SKILL.md.

Common situations: A special file was created at the skill path by another process or a misconfigured tooling script; a name that looks like a file is actually a named pipe set up for IPC inside the workspace.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at kernel/util/skill_manage.go:213

		return "encoding"
	case errors.Is(err, ErrSkillTooLarge):
		return "tooLarge"
	}
	return ""
}

func readManagedSkillSource(root *os.Root, p string) (string, error) {
	file, err := root.Open(p)
	if err != nil {
		return "", err
	}
	defer file.Close()
	info, err := file.Stat()
	if err != nil {
		return "", err
	}
	if !info.Mode().IsRegular() {
		return "", errors.New("skill source is not a regular file")
	}
	if info.Size() > maxManagedSkillSourceSize {
		return "", ErrSkillTooLarge
	}
	content, err := io.ReadAll(io.LimitReader(file, maxManagedSkillSourceSize+1))
	if err != nil {
		return "", err
	}
	// UTF-8 BOM 随正文保留;二进制内容不会返回给文本编辑器。
	if err = validateManagedSkillSource(string(content)); err != nil {
		return "", err
	}
	return string(content), nil
}

// 写入临时文件并同步后替换,发生写入错误时保留原文及其换行和元数据。
func writeManagedSkillSource(root *os.Root, p, content string, create bool, revision string) error {
	if err := validateManagedSkillSource(content); err != nil {

View on GitHub (pinned to 9f775e8a12)