siyuan-note/siyuan · error
CardDAV: address book path is invalid
Error message
CardDAV: address book path is invalid
What it means
ErrorCardDavBookPathInvalid is returned by ParseAddressPath (kernel/model/carddav.go:133-136) when the parent portion of an address URL does not sit at exactly cardDavPathDepth_AddressBook — i.e. the path does not have the shape /carddav/principals/main/contacts/<book>/<file>.vcf. It is a structural URL validation error thrown before any storage lookup, distinguishing 'malformed book path' from 'book exists but was not found'.
Source
Thrown at kernel/model/carddav.go:94
defaultAddressBook = carddav.AddressBook{
Path: CardDavDefaultAddressBookPath,
Name: CardDavDefaultAddressBookName,
Description: "Default address book",
MaxResourceSize: addressBookMaxResourceSize,
SupportedAddressData: addressBookSupportedAddressData,
}
contacts = Contacts{
loaded: false,
changed: false,
lock: sync.Mutex{},
books: sync.Map{},
booksMetaData: []*carddav.AddressBook{},
}
ErrorCardDavPathInvalid = errors.New("CardDAV: path is invalid")
ErrorCardDavBookNotFound = errors.New("CardDAV: address book not found")
ErrorCardDavBookPathInvalid = errors.New("CardDAV: address book path is invalid")
ErrorCardDavAddressNotFound = errors.New("CardDAV: address not found")
ErrorCardDavAddressFileExtensionNameInvalid = errors.New("CardDAV: address file extension name is invalid")
)
// ImportAddressBook imports an address book from a vCard file (*.vcf)
func ImportAddressBook(addressBookPath, cardContent string) (addresses []*AddressObject, err error) {
// TODO: Check whether the path is valid (PathDepth: Address)
// TODO: Check whether the address book exists
// TODO: Decode the card content
// TODO: Save the cards to the file system
return
}
// ExportAddressBook exports an address book to a vCard file (*.vcf)
func ExportAddressBook(addressBookPath string) (cardContent string, err error) {
// TODO: Check whether the path is valid (PathDepth: AddressBook)
// TODO: Check whether the address book existsView on GitHub (pinned to 8641553a1f)
Solutions
- Ensure the URL has exactly the 6-segment shape /carddav/principals/main/contacts/<book>/<id>.vcf; add the missing address book segment or remove extra ones.
- Build address paths from the constants (CardDavHomeSetPath + "/" + bookName + "/" + id + ".vcf") instead of string concatenation of guesses.
- Point the client at a real address book URL (e.g. CardDavDefaultAddressBookPath) rather than the home set when performing per-card operations.
- Check GetCardDavPathDepth(bookPath) == 5 (cardDavPathDepth_AddressBook) in test/verification code before calling address APIs.
Example fix
// before: card placed directly under the home set (depth 4 parent)
contacts.PutAddressObject("/carddav/principals/main/contacts/c1.vcf", card, nil) // ErrorCardDavBookPathInvalid
// after: include the address book segment
contacts.PutAddressObject(model.CardDavDefaultAddressBookPath+"/c1.vcf", card, nil) Defensive patterns
Strategy: validation
Validate before calling
addressPath := "/carddav/principals/main/contacts/default/c1.vcf"
bookPath, id, err := model.ParseAddressPath(addressPath)
if err != nil {
return fmt.Errorf("address path %s malformed: %w", addressPath, err)
}
_ = bookPath; _ = id Type guard
func isAddressPath(p string) bool {
_, _, err := model.ParseAddressPath(p)
return err == nil
} Try / catch
if _, _, err := model.ParseAddressPath(addressPath); err != nil {
if errors.Is(err, model.ErrorCardDavBookPathInvalid) {
return fmt.Errorf("URL must be /carddav/principals/main/contacts/<book>/<file>.vcf, got %s", addressPath)
}
return err
} Prevention
- Compose address URLs from constants: CardDavHomeSetPath + "/<book>/" + id + ".vcf"; never hand-concatenate partial paths.
- Point clients at an address book URL, not the home set, for per-card operations.
- Assert path depth 5 for book segments in tests before touching address APIs.
- Normalize client URLs (strip trailing slash, resolve relative references) before parsing.
When it happens
Trigger: ParseAddressPath (called from GetAddress, DeleteAddress, PutAddressObject, etc.) receives an address path whose addressBookPath depth is not 5: e.g. an address placed directly in the home set (.../contacts/x.vcf), nested extra segments (.../contacts/a/b/x.vcf), or querying a book path itself as if it were an address.
Common situations: A client configured with the home set as its 'address book' URL and then appending only the card file name; hand-built paths with a missing or duplicated segment; older client versions or migrations that stored pre-hierarchy CardDAV URLs; integration scripts using the wrong base path constant.
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
- CardDAV: path is invalid
- CalDAV: calendar object path is invalid
- CardDAV: address book not found
- invalid path
- asset path must be absolute
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/63c4da7f460f1141.
Report an issue: GitHub.