passbolt/passbolt_api · error · BadRequestException
V4 related fields are not supported for V5.
Error message
V4 related fields are not supported for V5.
What it means
After confirming the payload is a valid V5 payload (all V5 metadata fields present), MetadataTagDto::validate() rejects any V4 field (currently 'slug') that is non-null, throwing this 400 BadRequestException. V4 and V5 representations are mutually exclusive in one request to prevent ambiguous writes.
Solutions
- Remove 'slug' (set it to null / omit the key) when sending V5 metadata fields — the slug lives inside the encrypted metadata.
- Audit serializers/DTO mappers so V4 props are stripped when a V5 payload is built.
- If you need the plain-text slug, put it in the metadata's clear-text object (PASSBOLT_TAG_METADATA.slug) before encryption.
- Send a pure V4 payload ({slug} only) if the Metadata plugin is not enabled.
Example fix
// before: mixed payload
POST /tags { "slug": "my-tag", "metadata": "<encrypted>", "metadata_key_id": "<uuid>", "metadata_key_type": "shared_key" }
// after: v5 only
POST /tags { "metadata": "<encrypted>", "metadata_key_id": "<uuid>", "metadata_key_type": "shared_key" } Defensive patterns
Strategy: validation
Validate before calling
if (body.metadata != null && (body.slug != null)) throw new Error('cannot mix v4 slug with v5 metadata fields'); Type guard
const isMixedV4V5 = (b) => b.metadata != null && b.slug != null;
Try / catch
try { await api.put(`/tags/${id}`, body); } catch (e) { if (e.response?.status === 400 && /V4 related fields/.test(e.response?.data?.message)) body = stripV4Fields(body); throw e; } Prevention
- Omit or null out 'slug' in all V5 tag payloads
- Configure serializers to exclude V4 props once V5 is active
- Put the human-readable slug inside the encrypted metadata object instead
When it happens
Trigger: Sending both slug and the V5 metadata fields in the same tag create/update body, e.g. {slug: 'my-tag', metadata: ..., metadata_key_id: ..., metadata_key_type: ...}.
Common situations: Clients keeping the old 'slug' key in payloads for backward compatibility while adding V5 fields; generic serializers that always emit every entity property including null-able slug defaults; migrated integrations where slug is defaulted to '' rather than omitted.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Few fields are missing for the V5.
- Could not delete favorite.
- Could not save the account recovery setting.
- Could not validate comment data.
- Could not validate settings.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/87a67172ff88bb57.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Tags/src/Model/Dto/MetadataTagDto.php:195
throw new BadRequestException($msg);
}
// Now that we know that we have a valid v5 payload, we check that no v4 fields are in the payload
$v4SuperfluousFields = [];
foreach (self::V4_META_PROPS as $v4Field) {
if (array_key_exists($v4Field, $data) && !is_null($data[$v4Field])) {
$v4SuperfluousFields[] = $v4Field;
}
}
if (!empty($v4SuperfluousFields)) {
$msg = __('V4 related fields are not supported for V5.');
if (Configure::read('debug')) {
Log::error($msg);
Log::error(__('Superfluous fields: {0}', implode(', ', $v4SuperfluousFields)));
}
throw new BadRequestException($msg);
}
}
/**
* Returns metadata array in cleartext form as per v5 format.
*
* @return array
*/
public function getClearTextMetadata(): array
{
return [
'object_type' => 'PASSBOLT_TAG_METADATA',
'slug' => $this->slug,
// below fields are null for now will be added in future
'color' => null,
'description' => null,
'icon' => null,
];View on GitHub (pinned to 31c1bbc10f)