siyuan-note/siyuan · error
Invalid template directory
Error message
Invalid template directory
What it means
DocSaveAsTemplate (/api/template/docSaveAsTemplate) accepts an optional `directory` field that must be a JSON string. If the field is present but is null, or cannot be unmarshalled into a string, decoding fails immediately with 'Invalid template directory'. Unlike databaseMode (which falls back to a sentinel), directory is treated as a hard input error.
Solutions
- Send directory as a plain string, e.g. {"directory":"templates"}
- Omit the directory field entirely if you do not need a subdirectory
- Check the client value for null/undefined before including it in the payload
Example fix
// before
{"id":"20240101120000-abc", "name":"tpl", "overwrite":false, "directory":null}
// after
{"id":"20240101120000-abc", "name":"tpl", "overwrite":false, "directory":"my-templates"} Defensive patterns
Strategy: validation
Validate before calling
if ('directory' in p && (p.directory === null || typeof p.directory !== 'string')) throw new Error('directory must be a string'); Type guard
const isDirectory = (v) => v === undefined || typeof v === 'string';
Try / catch
const res = await fetchPost('/api/template/docSaveAsTemplate', payload); if (res.code !== 0) console.error(res.msg); Prevention
- Delete the directory key instead of sending null
- Ensure UI inputs yield strings, not numbers
- Omit optional fields you do not set
When it happens
Trigger: POSTing {"id":"...","name":"...","overwrite":true,"directory":null} or directory as a number/boolean/object, e.g. {"directory":123}.
Common situations: A client serializing an undefined variable to null and including the key anyway; a UI dropdown storing a numeric directory index instead of the string name; copy/paste payloads where the directory was quoted incorrectly.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- createDocTree definition must be a list
- createDocTree document must be a dictionary
- Field [rootIDs] should be of type [Array]
- Field [ ] has an invalid type
- Field [ ] should be of type [Array]
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/5e8a94e23e402f83.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/template.go:40
}
if request.ID, err = legacyField[string](fields, "id", "String", true); err != nil {
return request, err
}
if request.Name, err = legacyField[string](fields, "name", "String", true); err != nil {
return request, err
}
if request.Overwrite, err = legacyField[bool](fields, "overwrite", "Boolean", true); err != nil {
return request, err
}
request.DatabaseMode = "copy"
if raw, exists := fields["databaseMode"]; exists {
if string(raw) == "null" || json.Unmarshal(raw, &request.DatabaseMode) != nil {
request.DatabaseMode = "invalid"
}
}
if raw, exists := fields["directory"]; exists {
if string(raw) == "null" || json.Unmarshal(raw, &request.Directory) != nil {
return request, fmt.Errorf("Invalid template directory")
}
}
return
}
}
type RenderSprigRequest struct {
Template string `json:"template"`
}
type TemplateDocumentRequest struct {
ID string `json:"id"`
}
type TemplateDocumentInfo struct {
Name string `json:"name"`
Directory string `json:"directory"`
HasDatabase bool `json:"hasDatabase"`View on GitHub (pinned to 9f775e8a12)