siyuan-note/siyuan · error

create import dir failed

Error message

create import dir failed: %s

What it means

For non-HTML/text content types, WebFetch saves the body as a file under <TempDir>/import. Before writing it calls os.MkdirAll(importDir, 0755); failure (permission denied on the temp dir, path occupied by a regular file, read-only filesystem) is wrapped as 'create import dir failed: <cause>'.

Solutions

  1. Inspect the wrapped cause after 'create import dir failed: ' to distinguish EEXIST-as-file vs EACCES vs EROFS
  2. Check that TempDir exists, is writable by the kernel user, and contains no regular file named 'import'
  3. Fix permissions: chown/chmod the temp directory for the process user
  4. If running in a container, mount a writable volume at the temp path

Example fix

// before
// file named 'import' blocks directory creation
$ rm $TMPDIR/import   # remove the colliding regular file

// after
$ mkdir -p $TMPDIR/import && chmod u+rwx $TMPDIR/import
Defensive patterns

Strategy: try-catch

Validate before calling

importDir := filepath.Join(TempDir, "import")
if fi, err := os.Stat(importDir); err == nil && !fi.IsDir() {
    return errors.New("temp 'import' path is occupied by a regular file")
}

Try / catch

_, err := WebFetch(url, format)
if err != nil && strings.Contains(err.Error(), "create import dir failed") {
    // inspect wrapped errno: EACCES -> fix perms, EROFS -> mount writable tmp, EEXIST-as-file -> remove collision
}

Prevention

When it happens

Trigger: os.MkdirAll cannot create the import directory because a file named 'import' already exists in TempDir, the temp directory's permissions changed, or the disk/filesystem is read-only.

Common situations: Running the kernel as a different user after TempDir was created by another account; containerized deployments with read-only tmpfs; a stale file colliding with the 'import' directory name; disk-full or quota conditions surfacing as mkdir errors.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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

Appendix: source

Thrown at kernel/util/webfetch.go:80

	contentType := resp.Header.Get("Content-Type")
	maxReadBytes := int64(maxWebFetchBytes)
	if !strings.HasPrefix(contentType, "text/html") && !strings.HasPrefix(contentType, "text/plain") {
		maxReadBytes = maxWebFetchFileBytes
	}
	if resp.ContentLength > maxReadBytes {
		return "", errors.New("response too large")
	}

	body, err := io.ReadAll(io.LimitReader(resp.Body, maxReadBytes))
	if err != nil {
		return "", errors.New("read body failed: " + err.Error())
	}

	if !strings.HasPrefix(contentType, "text/html") && !strings.HasPrefix(contentType, "text/plain") {
		importDir := filepath.Join(TempDir, "import")
		if merr := os.MkdirAll(importDir, 0755); merr != nil {
			return "", errors.New("create import dir failed: " + merr.Error())
		}
		filename := extractFilename(rawURL, contentType)
		filePath := filepath.Join(importDir, filename)
		if werr := os.WriteFile(filePath, body, 0644); werr != nil {
			return "", errors.New("write file failed: " + werr.Error())
		}
		return fmt.Sprintf("Saved to: %s (%d bytes)", filePath, len(body)), nil
	}

	htmlStr := string(body)

	isHTML := strings.HasPrefix(contentType, "text/html")
	if !isHTML {
		return truncateRunes(htmlStr, maxWebFetchChars), nil
	}

	if htmlStr == "" {
		return "", nil

View on GitHub (pinned to 9f775e8a12)