Skip to content

PUTing VCARD with email hook enabled causes 400 Bad Request #2038

@wunter8

Description

@wunter8

I am using DAVx5 to sync contacts from Android to Radicale. When syncing a new contact, DAVx5 would show a 400 error. I enabled debug logging on Radicale and noticed that the email hook is being triggered for the new contact, resulting in the error: ValueError: Invalid component type: 'VCARD', expected 'VCALENDAR'.

After disabling the email hook, the same PUT request results in a 201 Created or 204 No Content.

Even with the email hook enabled, though, the VCARD record is created and a subsequent GET for the record works. It's just the unexpected 400 Bad Request response that is the issue.

Limiting the hook to VCALENDAR collections seems like it would fix the issue, as mentioned here: #1923 (comment)

Here are the logs and the VCARD:

Radicale Logs

radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [INFO] PUT request for '/user/def-addressbook/56f55e0e-d6c7-4240-9ea5-505780bdcaa8.vcf' received from 10.25.76.1 (forwarded for '2604:f580:1:79:b867:5ca3:68e4:7f9b') using 'curl/7.81.0'
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Request header:
radicale-1  |  {'CONTENT_LENGTH': '247',
radicale-1  |   'CONTENT_TYPE': 'text/plain',
radicale-1  |   'GATEWAY_INTERFACE': 'CGI/1.1',
radicale-1  |   'HTTP_ACCEPT': '*/*',
radicale-1  |   'HTTP_ACCEPT_ENCODING': 'gzip',
radicale-1  |   'HTTP_AUTHORIZATION': 'Basic **masked**',
radicale-1  |   'HTTP_HOST': '**masked**',
radicale-1  |   'HTTP_USER_AGENT': 'curl/7.81.0',
radicale-1  |   'HTTP_VIA': '2.0 Caddy',
radicale-1  |   'HTTP_X_FORWARDED_FOR': '**masked**',
radicale-1  |   'HTTP_X_FORWARDED_HOST': '**masked**',
radicale-1  |   'HTTP_X_FORWARDED_PROTO': 'https',
radicale-1  |   'PATH_INFO': '/user/def-addressbook/56f55e0e-d6c7-4240-9ea5-505780bdcaa8.vcf',
radicale-1  |   'QUERY_STRING': '',
radicale-1  |   'REMOTE_ADDR': '**masked**',
radicale-1  |   'REMOTE_HOST': '',
radicale-1  |   'REQUEST_METHOD': 'PUT',
radicale-1  |   'SCRIPT_NAME': '',
radicale-1  |   'SERVER_NAME': 'c9f3cc006623',
radicale-1  |   'SERVER_PORT': '5232',
radicale-1  |   'SERVER_PROTOCOL': 'HTTP/1.1',
radicale-1  |   'SERVER_SOFTWARE': 'WSGIServer/0.2',
radicale-1  |   'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>,
radicale-1  |   'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>,
radicale-1  |   'wsgi.input': <_io.BufferedReader name=7>,
radicale-1  |   'wsgi.multiprocess': False,
radicale-1  |   'wsgi.multithread': True,
radicale-1  |   'wsgi.run_once': False,
radicale-1  |   'wsgi.url_scheme': 'http',
radicale-1  |   'wsgi.version': (1, 0)}
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Sanitized path: '/user/def-addressbook/56f55e0e-d6c7-4240-9ea5-505780bdcaa8.vcf'
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Read content of htpasswd file start: '/etc/radicale/users'
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Read content of htpasswd file done: '/etc/radicale/users' (entries: 1, duplicates: 0, errors: 0)
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Login verification successful for user: 'user' (htpasswd/autodetect/BCRYPT)
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [INFO] Successful login: 'user' (htpasswd)
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Request content (sha256sum): a8cdcd7432c52cfec8b1db189bfcc7db47027ac21ee0d7eabcf4e15a82e0e0d5
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Request content:
radicale-1  |  BEGIN:VCARD
radicale-1  |  VERSION:3.0
radicale-1  |  PRODID:+//IDN bitfire.at//DAVx5/4.5.4-ose ez-vcard/0.12.1 (ez-vcard/0.12.1)
radicale-1  |  UID:56f55e0e-d6c7-4240-9ea5-505780bdcaa8
radicale-1  |  FN:New Contact
radicale-1  |  N:Contact;New;;;
radicale-1  |  TEL;TYPE=cell:+1 555-123-6789
radicale-1  |  REV:2026-03-22T17:25:15Z
radicale-1  |  END:VCARD
radicale-1  |
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] PUT request contains item with UID '56f55e0e-d6c7-4240-9ea5-505780bdcaa8' size 247 below limit 10000000: '/user/def-addressbook/56f55e0e-d6c7-4240-9ea5-505780bdcaa8.vcf'
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Received notification_item: {'type': 'upsert', 'point': 'user/def-addressbook', '_content_legacy': 'BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:+//IDN bitfire.at//DAVx5/4.5.4-ose ez-vcard/0.12.1 (ez-vcard/0.12.1)\r\nUID:56f55e0e-d6c7-4240-9ea5-505780bdcaa8\r\nFN:New Contact\r\nN:Contact;New;;;\r\nREV:2026-03-22T17:25:15Z\r\nTEL;TYPE=cell:+1 555-123-6789\r\nEND:VCARD\r\n', 'uid': None, 'new_content': 'BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:+//IDN bitfire.at//DAVx5/4.5.4-ose ez-vcard/0.12.1 (ez-vcard/0.12.1)\r\nUID:56f55e0e-d6c7-4240-9ea5-505780bdcaa8\r\nFN:New Contact\r\nN:Contact;New;;;\r\nREV:2026-03-22T17:25:15Z\r\nTEL;TYPE=cell:+1 555-123-6789\r\nEND:VCARD\r\n', 'old_content': 'BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:+//IDN bitfire.at//DAVx5/4.5.4-ose ez-vcard/0.12.1 (ez-vcard/0.12.1)\r\nUID:56f55e0e-d6c7-4240-9ea5-505780bdcaa8\r\nFN:New Contact\r\nN:Contact;New;;;\r\nREV:2026-03-22T17:25:15Z\r\nTEL;TYPE=cell:+1 555-123-6789\r\nEND:VCARD\r\n'}
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [WARNING] Bad PUT request on '/user/def-addressbook/56f55e0e-d6c7-4240-9ea5-505780bdcaa8.vcf' (upload): Invalid component type: 'VCARD', expected 'VCALENDAR'
radicale-1  | Traceback (most recent call last):
radicale-1  |   File "/app/lib/python3.14/site-packages/radicale/app/put.py", line 356, in do_PUT
radicale-1  |     self._hook.notify(hook_notification_item)
radicale-1  |     ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
radicale-1  |   File "/app/lib/python3.14/site-packages/radicale/hook/email/__init__.py", line 940, in notify
radicale-1  |     self._process_event_and_notify(notification_item)
radicale-1  |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
radicale-1  |   File "/app/lib/python3.14/site-packages/radicale/hook/email/__init__.py", line 969, in _process_event_and_notify
radicale-1  |     if not ics_contents_contains_event(contents=new_item_str):
radicale-1  |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
radicale-1  |   File "/app/lib/python3.14/site-packages/radicale/hook/email/__init__.py", line 175, in ics_contents_contains_event
radicale-1  |     return read_ics_event(contents) is not None
radicale-1  |            ~~~~~~~~~~~~~~^^^^^^^^^^
radicale-1  |   File "/app/lib/python3.14/site-packages/radicale/hook/email/__init__.py", line 165, in read_ics_event
radicale-1  |     cal: Calendar = Calendar(vobject_item=v_cal)
radicale-1  |                     ~~~~~~~~^^^^^^^^^^^^^^^^^^^^
radicale-1  |   File "/app/lib/python3.14/site-packages/radicale/hook/email/__init__.py", line 529, in __init__
radicale-1  |     super().__init__(vobject_item, "VCALENDAR")
radicale-1  |     ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
radicale-1  |   File "/app/lib/python3.14/site-packages/radicale/hook/email/__init__.py", line 277, in __init__
radicale-1  |     raise ValueError("Invalid component type: %r, expected %r" %
radicale-1  |                      (vobject_item.name, component_type))
radicale-1  | ValueError: Invalid component type: 'VCARD', expected 'VCALENDAR'
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Response content: suppressed by config/option [logging] response_content_on_debug
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [DEBUG] Response header: suppressed by config/option [logging] response_header_on_debug
radicale-1  | [2026-03-23 14:32:52 +0000] [1/Thread-1 (process_request_thread)] [INFO] PUT response status for '/user/def-addressbook/56f55e0e-d6c7-4240-9ea5-505780bdcaa8.vcf' in 0.084 seconds gzip 31 bytes: 400 Bad Request

VCARD

BEGIN:VCARD
VERSION:3.0
PRODID:+//IDN bitfire.at//DAVx5/4.5.4-ose ez-vcard/0.12.1 (ez-vcard/0.12.1)
UID:56f55e0e-d6c7-4240-9ea5-505780bdcaa8
FN:New Contact
N:Contact;New;;;
TEL;TYPE=cell:+1 555-123-6789
REV:2026-03-22T17:25:15Z
END:VCARD

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions