siyuan-note/siyuan · error

read imported notebook conf [%s] failed: %w

Error message

read imported notebook conf [%s] failed: %w

What it means

Thrown by validateImportedNotebookIdentities during Data.zip import when filelock.ReadFile fails reading the .siyuan/conf.json of an imported notebook. The conf.json file was confirmed to exist via filelock.IsExist, but the subsequent read returned an error. The error wraps the underlying I/O error with the boxID for context.

Source

Thrown at kernel/model/import.go:1053

		return nil, err
	}

	var encryptedBoxIDs []string
	for _, entry := range dirs {
		if !entry.IsDir() || !ast.IsNodeIDPattern(entry.Name()) {
			continue
		}

		boxID := entry.Name()
		boxDir := filepath.Join(tmpDataPath, boxID)
		confPath := filepath.Join(boxDir, ".siyuan", "conf.json")
		backupPath := filepath.Join(boxDir, ".siyuan", notebookCryptoBackupFilename)

		var boxConf *conf.BoxConf
		if filelock.IsExist(confPath) {
			data, readErr := filelock.ReadFile(confPath)
			if readErr != nil {
				return nil, fmt.Errorf("read imported notebook conf [%s] failed: %w", boxID, readErr)
			}
			boxConf = conf.NewBoxConf()
			if unmarshalErr := gulu.JSON.UnmarshalJSON(data, boxConf); unmarshalErr != nil {
				return nil, fmt.Errorf("parse imported notebook conf [%s] failed: %w", boxID, unmarshalErr)
			}
		}

		var backup *conf.BoxEncryption
		if filelock.IsExist(backupPath) {
			backup, err = readBoxEncryptionFile(backupPath)
			if err != nil {
				return nil, fmt.Errorf("invalid imported notebook identity [%s]: %w", boxID, err)
			}
		}

		var boxCrypt *conf.BoxEncryption
		if boxConf != nil && boxConf.Encrypted {
			if boxConf.BoxCrypt != nil && validateBoxEncryption(boxConf.BoxCrypt) == nil {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Check file permissions on the .siyuan/conf.json inside the Data.zip's notebook directory.
  2. Re-export the Data.zip from the source SiYuan instance to rule out archive corruption.
  3. Verify the temp directory used for extraction is writable and not on a failing disk.
  4. Inspect the wrapped error (%w) in the returned error for the specific filesystem error code.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before validateImportedNotebookIdentities, pre-check conf.json readability
func preCheckConfReadable(tmpDataPath, boxID string) error {
    confPath := filepath.Join(tmpDataPath, boxID, ".siyuan", "conf.json")
    if !filelock.IsExist(confPath) {
        return nil // absent is fine
    }
    f, err := os.Open(confPath)
    if err != nil {
        return fmt.Errorf("conf.json for notebook %s is not readable: %w", boxID, err)
    }
    f.Close()
    return nil
}

Try / catch

encryptedBoxIDs, err := validateImportedNotebookIdentities(tmpDataPath)
if err != nil {
    if strings.Contains(err.Error(), "read imported notebook conf") {
        // The conf.json exists but is unreadable — suggest re-export
        logging.LogErrorf("conf.json read failed during import: %s", err)
    }
}

Prevention

When it happens

Trigger: Calling validateImportedNotebookIdentities (from ImportData) where a notebook directory under the extracted Data.zip contains a .siyuan/conf.json that exists but cannot be read. The check is at import.go:1050-1053.

Common situations: Permission denied on the conf.json file. File deleted between the IsExist check and the ReadFile call (race condition). Filesystem error on the temp volume. Corrupted filesystem sector. File locked exclusively by another process.

Related errors


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