siyuan-note/siyuan · error

invalid import token

Error message

invalid import token

What it means

claimStagedSYImport validates the opaque token returned by the staging step before renaming the staged .sy zip out of the staging directory. isValidSYImportToken rejects tokens that are not well-formed (wrong charset/length), so a malformed or fabricated token yields 'invalid import token'.

Solutions

  1. Pass the exact token string returned by the stage/upload response, unmodified.
  2. Verify the token matches isValidSYImportToken's expected format before calling.
  3. If the original response was lost, restart the import to get a fresh token.
  4. Ensure the token is not wrapped in quotes or whitespace from copy/paste.

Example fix

// before
claim("../../etc/tmp-import.zip") // invalid

// after
token := stageResponse.data.token
if !isValidSYImportToken(token) { /* re-stage */ }
claim(token)
Defensive patterns

Strategy: validation

Validate before calling

if (!/^[A-Za-z0-9_-]{6,64}$/.test(token)) throw new Error("malformed import token")

Type guard

function isValidImportToken(t) { return typeof t === "string" && /^[A-Za-z0-9_-]+$/.test(t) }

Try / catch

try { await claim(token) }
catch (e) { if (e.message === "invalid import token") restageAndRetry() else throw e }

Prevention

When it happens

Trigger: Calling the claim API with a token that was never issued, hand-crafted, truncated, or contains characters outside the allowed token alphabet (e.g. path separators — also a traversal guard).

Common situations: Client stores the token incorrectly (URL-encoded/decoded wrongly); retry after the token expired uses a stale/guessed value; attacker probes the endpoint with arbitrary strings.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at kernel/api/import.go:227

		return
	}
	for {
		token = gulu.Rand.String(32)
		_, statErr := os.Stat(stagedSYImportPath(token))
		if os.IsNotExist(statErr) {
			break
		}
		if statErr != nil {
			return "", statErr
		}
	}
	err = os.Rename(srcPath, stagedSYImportPath(token))
	return
}

func claimStagedSYImport(token string) (path string, err error) {
	if !isValidSYImportToken(token) {
		return "", errors.New("invalid import token")
	}
	stagedSYImportLock.Lock()
	defer stagedSYImportLock.Unlock()
	cleanupStagedSYImports()
	srcPath := stagedSYImportPath(token)
	if _, err = os.Stat(srcPath); err != nil {
		if os.IsNotExist(err) {
			err = errors.New("import task not found or expired")
		}
		return "", err
	}
	path = filepath.Join(stagedSYImportDir(), token+"-importing.zip")
	err = os.Rename(srcPath, path)
	return
}

func cleanupStagedSYImports() {
	entries, err := os.ReadDir(stagedSYImportDir())

View on GitHub (pinned to 9f775e8a12)