{"record":{"id":"56fd626c4fe0eddd","repo":"nextcloud/server","slug":"the-http-nextcloud-com-ns-param-filter-requires","errorCode":null,"errorMessage":"The {http://nextcloud.com/ns}param-filter requires a valid property attribute","messagePattern":"The (.+?)param-filter requires a valid property attribute","errorType":"http","errorClass":"Sabre\\DAV\\Exception\\BadRequest","httpStatus":400,"severity":"error","filePath":"apps/dav/lib/CalDAV/Search/Xml/Filter/ParamFilter.php","lineNumber":33,"sourceCode":"use Sabre\\Xml\\XmlDeserializable;\n\nclass ParamFilter implements XmlDeserializable {\n\n\t/**\n\t * @param Reader $reader\n\t * @throws BadRequest\n\t * @return string\n\t */\n\t#[\\Override]\n\tpublic static function xmlDeserialize(Reader $reader) {\n\t\t$att = $reader->parseAttributes();\n\t\t$property = $att['property'];\n\t\t$parameter = $att['name'];\n\n\t\t$reader->parseInnerTree();\n\n\t\tif (!is_string($property)) {\n\t\t\tthrow new BadRequest('The {' . SearchPlugin::NS_Nextcloud . '}param-filter requires a valid property attribute');\n\t\t}\n\t\tif (!is_string($parameter)) {\n\t\t\tthrow new BadRequest('The {' . SearchPlugin::NS_Nextcloud . '}param-filter requires a valid parameter attribute');\n\t\t}\n\n\t\treturn [\n\t\t\t'property' => $property,\n\t\t\t'parameter' => $parameter,\n\t\t];\n\t}\n}\n","sourceCodeStart":15,"sourceCodeEnd":45,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CalDAV/Search/Xml/Filter/ParamFilter.php#L15-L45","documentation":"Thrown while deserializing {http://nextcloud.com/ns}param-filter in a search REPORT: the element must carry a property attribute (the iCal property the parameter belongs to, e.g. PARTSTAT), and ParamFilter::xmlDeserialize() throws Sabre\\DAV\\Exception\\BadRequest (HTTP 400) when $att['property'] is not a string.","triggerScenarios":"Sending <n:param-filter name=\"PARTSTAT\"/> without property=\"ATTENDEE\" inside <n:prop-filter>.","commonSituations":"Confusing param-filter with prop-filter and omitting the property attribute; hand-crafted XML from docs examples that only show the name attribute.","solutions":["Add the property attribute naming the component property that owns the parameter: <n:param-filter property=\"ATTENDEE\" name=\"PARTSTAT\"/>","Keep param-filter nested inside a prop-filter that targets the same property","Validate the filter tree structure before sending the REPORT"],"exampleFix":"// before\n<n:param-filter name=\"PARTSTAT\"/>\n\n// after\n<n:prop-filter name=\"ATTENDEE\">\n  <n:param-filter name=\"PARTSTAT\"/>\n</n:prop-filter>","handlingStrategy":"validation","validationCode":"function buildParamFilter(string $property, string $name): string {\n    foreach (['property' => $property, 'name' => $name] as $v) {\n        if ($v === '' || !ctype_upper($v)) {\n            throw new InvalidArgumentException('param-filter needs non-empty property and name');\n        }\n    }\n    return \"<n:param-filter property=\\\"{$property}\\\" name=\\\"{$name}\\\"/>\";\n}","typeGuard":"function isValidParamFilterAttrs(array $att): bool {\n    return isset($att['property'], $att['name'])\n        && is_string($att['property']) && $att['property'] !== ''\n        && is_string($att['name']) && $att['name'] !== '';\n}","tryCatchPattern":"try {\n    $client->request('REPORT', $calendarUri, $xmlBody);\n} catch (\\Sabre\\Http\\ClientException $e) {\n    if ($e->getResponse()?->getStatus() === 400) { /* add property=\"...\" to param-filter */ }\n}","preventionTips":["Remember param-filter takes BOTH property and name attributes","Nest param-filter inside the prop-filter for the same property","Document the filter grammar next to your XML builder to prevent regressions"],"tags":["caldav","xml","search","nextcloud","bad-request","param-filter"],"backgroundTag":"webdav-400-bad-request","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}