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 exists

View on GitHub (pinned to 8641553a1f)

Solutions

  1. 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.
  2. Build address paths from the constants (CardDavHomeSetPath + "/" + bookName + "/" + id + ".vcf") instead of string concatenation of guesses.
  3. Point the client at a real address book URL (e.g. CardDavDefaultAddressBookPath) rather than the home set when performing per-card operations.
  4. 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

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/63c4da7f460f1141. Report an issue: GitHub.