{"record":{"id":"ab42f36e338dffb6","repo":"monicahq/monica","slug":"no-address-book-found","errorCode":null,"errorMessage":"No address book found","messagePattern":"No address book found","errorType":"exception","errorClass":"DavClientException","httpStatus":null,"severity":"error","filePath":"app/Domains/Contact/DavClient/Services/Utils/AddressBookGetter.php","lineNumber":111,"sourceCode":"                // Catch error\n            }\n        }\n\n        // If no address book found, try with the service url\n        if ($addressBookUrl === null) {\n            $serviceUrl = $this->client->getServiceUrl();\n\n            if ($serviceUrl !== null) {\n                try {\n                    $addressBookUrl = $this->getAddressBookForUri($serviceUrl);\n                } catch (\\Illuminate\\Http\\Client\\RequestException $e) {\n                    // Catch error\n                }\n            }\n        }\n\n        if ($addressBookUrl === null) {\n            throw new DavClientException('No address book found');\n        }\n\n        $addressBookUrl = $this->client->path(parse_url($addressBookUrl, PHP_URL_PATH));\n\n        if (! Str::contains($addressBookUrl, 'https://www.googleapis.com')) {\n            // Check the OPTIONS of the server\n            $this->checkOptions(true, $addressBookUrl);\n        }\n\n        return $addressBookUrl;\n    }\n\n    /**\n     * Calculate address book base uri.\n     */\n    private function getAddressBookForUri(string $uri = ''): ?string\n    {\n        // Get the principal of this account","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/monicahq/monica/blob/e08e91734170b6bbd582cb578532c3948196124e/app/Domains/Contact/DavClient/Services/Utils/AddressBookGetter.php#L93-L129","documentation":"AddressBookGetter::getAddressBookBaseUri() tries three strategies to locate an address book collection: (1) walk the supplied URI path segment by segment with Depth-0 PROPFINDs looking for a {card:}addressbook resourcetype, (2) fall back to principal discovery on the original path, (3) fall back to the /.well-known-derived service URL. Every strategy's HTTP errors are silently caught, so if all attempts end with null this DavClientException is thrown: the server answered, but no address book was found for those credentials at that URL.","triggerScenarios":"Subscribing with credentials/URL where no address book collection is discoverable: a freshly created radicale/Nextcloud user with zero address books, a CalDAV-only server, a Depth-1 PROPFIND on the home-set returning no addressbook child, or a 401 on every discovery PROPFIND (auth failure is swallowed and looks identical to 'not found').","commonSituations":"New remote account without an address book created yet, wrong username format (UPN vs email), base_uri aimed at a CalDAV endpoint, or credentials that fail authentication so each discovery request silently errors out.","solutions":["Create at least one address book in the remote server's UI for that account, then retry the subscription","Point base_uri directly at the address book collection (e.g. https://cloud.example.com/remote.php/dav/addressbooks/users/USER/personal/) so the Depth-0 walk succeeds","Confirm discovery works: curl -u user:pass -X PROPFIND -H 'Depth: 1' <home-set-url> must list a child whose resourcetype includes addressbook","Verify the discovery requests are authenticated — a swallowed 401 is indistinguishable from 'no address book'"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Preflight: confirm the home-set actually contains an addressbook collection before subscribing\n$books = $davClient->propfind('{DAV:}resourcetype', depth: 1, url: $homeSetUrl);\n$hasAddressBook = collect($books)\n    ->contains(fn ($props) => Arr::get($props, '{DAV:}resourcetype')?->is('{urn:ietf:params:xml:ns:carddav}addressbook'));\n\nif (! $hasAddressBook) {\n    throw ValidationException::withMessages([\n        'base_uri' => 'No address book found on this server for these credentials. Create one first.',\n    ]);\n}","typeGuard":null,"tryCatchPattern":"try {\n    app(CreateAddressBookSubscription::class)->execute($data);\n} catch (DavClientException $e) {\n    if (str_contains($e->getMessage(), 'No address book found')) {\n        // guide the user: create an address book on the server, or supply the direct collection URL\n    }\n    throw $e;\n}","preventionTips":["Create at least one address book on the remote server before subscribing","Prefer the direct address book collection URL over the bare domain to skip fragile discovery","Remember a 401 during discovery is swallowed — always double-check credentials when this fires","Automate a pre-subscription PROPFIND check in onboarding flows to fail with an actionable message"],"tags":["carddav","dav","discovery","monica"],"backgroundTag":"carddav-addressbook-not-found","analyzedSha":"e08e91734170b6bbd582cb578532c3948196124e","analyzedAt":"2026-08-17T01:36:49.014Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}