{"record":{"id":"8bc3856cf08ac8bd","repo":"monicahq/monica","slug":"could-not-get-address-book-data","errorCode":null,"errorMessage":"Could not get address book data.","messagePattern":"Could not get address book data\\.","errorType":"exception","errorClass":"DavClientException","httpStatus":null,"severity":"error","filePath":"app/Domains/Contact/DavClient/Services/CreateAddressBookSubscription.php","lineNumber":52,"sourceCode":"            'author_must_belong_to_account',\n            'author_must_be_in_vault',\n            'author_must_be_vault_manager',\n            'vault_must_belong_to_account',\n        ];\n    }\n\n    /**\n     * Add a new Adress Book.\n     *\n     * @throws DavClientException\n     */\n    public function execute(array $data): AddressBookSubscription\n    {\n        $this->validateRules($data);\n\n        $addressBookData = $this->getAddressBookData($data);\n        if (! $addressBookData) {\n            throw new DavClientException(trans('Could not get address book data.'));\n        }\n\n        return $this->createAddressBook($data, $addressBookData);\n    }\n\n    private function createAddressBook(array $data, array $addressBookData): AddressBookSubscription\n    {\n        return AddressBookSubscription::create([\n            'user_id' => $this->author->id,\n            'vault_id' => $this->vault->id,\n            'username' => $data['username'],\n            'password' => $data['password'],\n            'uri' => $addressBookData['uri'],\n            'capabilities' => $addressBookData['capabilities'],\n        ]);\n    }\n\n    private function getAddressBookData(array $data): ?array","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/monicahq/monica/blob/e08e91734170b6bbd582cb578532c3948196124e/app/Domains/Contact/DavClient/Services/CreateAddressBookSubscription.php#L34-L70","documentation":"Thrown by Monica's address book subscription service when it cannot obtain address book data from a remote CardDAV server. CreateAddressBookSubscription::execute() validates the account/vault/author input, builds a DavClient from the supplied base_uri/username/password, and asks AddressBookGetter to discover the address book (uri, capabilities, name). If that discovery yields nothing usable, the service aborts before creating the AddressBookSubscription model. Note that in the current code the getter either returns an array or throws first ('No address book found', DavServerNotCompliantException, or a rethrown Guzzle ClientException), so this line acts as the defensive catch-all for a null return.","triggerScenarios":"Calling the 'add address book subscription' flow with a base_uri/username/password combination for which AddressBookGetter::execute() cannot produce address book data: the DAV endpoint is unreachable, credentials are rejected on every discovery PROPFIND, or the server exposes no address book. Typical concrete calls: POST with base_uri pointing at the server's web UI instead of its CardDAV endpoint, or the account password supplied where the provider requires an app-specific password (Google, Nextcloud).","commonSituations":"Wrong endpoint URL (web URL vs remote.php/dav or the Google CardDAV endpoint), missing app-specific password, reverse proxy stripping DAV headers so discovery fails, or a remote account that owns no address book yet.","solutions":["Verify endpoint and credentials outside Monica: curl -u user:pass -X PROPFIND -H 'Depth: 0' <base_uri> must return a 207 multi-status with a DAV header","Point base_uri at the documented CardDAV endpoint (e.g. https://cloud.example.com/remote.php/dav for Nextcloud, https://www.googleapis.com/.well-known/carddav for Google) and use an app password where required","Make sure the account on the remote server actually owns at least one address book (create one in the server UI first)","In the calling controller, catch DavClientException and surface it as a 422 validation error instead of letting it bubble up as a 500"],"exampleFix":"// before\npublic function store(Request $request)\n{\n    $subscription = app(CreateAddressBookSubscription::class)->execute($data); // throws -> 500\n}\n\n// after\nuse App\\Domains\\Contact\\DavClient\\Services\\Utils\\Dav\\DavClientException;\n\npublic function store(Request $request)\n{\n    try {\n        $subscription = app(CreateAddressBookSubscription::class)->execute($data);\n    } catch (DavClientException $e) {\n        throw ValidationException::withMessages([\n            'base_uri' => $e->getMessage(),\n        ]);\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Preflight: confirm the DAV endpoint answers an authenticated PROPFIND before subscribing\nuse Illuminate\\Support\\Facades\\Http;\n\n$response = Http::withBasicAuth($username, $password)\n    ->withHeaders(['Depth' => '0', 'Content-Type' => 'application/xml'])\n    ->send('PROPFIND', $baseUri);\n\nif ($response->status() !== 207) {\n    throw ValidationException::withMessages([\n        'base_uri' => \"DAV endpoint did not answer 207 (got {$response->status()}).\",\n    ]);\n}","typeGuard":null,"tryCatchPattern":"use App\\Domains\\Contact\\DavClient\\Services\\Utils\\Dav\\DavClientException;\nuse App\\Domains\\Contact\\DavClient\\Services\\Utils\\Dav\\DavServerNotCompliantException;\n\ntry {\n    $subscription = app(CreateAddressBookSubscription::class)->execute($data);\n} catch (DavClientException|DavServerNotCompliantException $e) {\n    // server answered but no usable address book / not compliant -> user-facing 422\n    throw ValidationException::withMessages(['base_uri' => $e->getMessage()]);\n} // Guzzle\\Exception\\ClientException may also propagate: let it bubble or map to 502","preventionTips":["Keep the exact CardDAV endpoint URL in configuration, not free-form user input where possible","For providers requiring app passwords, generate them before opening the subscription form","Run a manual PROPFIND with the same credentials whenever a subscription fails, to split credential problems from server problems","Map DavClientException to 422 in the controller so users see the reason instead of a 500"],"tags":["carddav","dav","monica","address-book","subscription"],"backgroundTag":"carddav-discovery-failed","analyzedSha":"e08e91734170b6bbd582cb578532c3948196124e","analyzedAt":"2026-08-17T01:36:49.014Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}