passbolt/passbolt_api · error · BadRequestException
The resource identifier should be a valid UUID.
Error message
The resource identifier should be a valid UUID.
What it means
Thrown by SecretsViewController::view() when the resourceId path parameter is not a valid UUID (Validation::uuid() fails). This is the first request-sanity check for GET /secrets/resource/{resourceId}, rejecting malformed identifiers as 400 Bad Request before any permission or database work.
Solutions
- Validate the resource id is a UUID before calling GET /secrets/resource/{id}.json
- Fetch resource ids from GET /resources.json rather than constructing them
- Check the client is not substituting the secret id or another entity's id
- Fix string interpolation/truncation in the URL builder
Example fix
// before
const secret = await api.get(`/secrets/resource/${resource.slug}.json`);
// after
if (!isUuid(resource.id)) throw new Error(`invalid resource id: ${resource.id}`);
const secret = await api.get(`/secrets/resource/${resource.id}.json`); Defensive patterns
Strategy: validation
Validate before calling
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (!UUID_RE.test(resourceId)) throw new Error(`invalid resource id: ${resourceId}`); Type guard
function isUuid(v) { return typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v); } Try / catch
try { await api.get(`/secrets/resource/${resourceId}.json`); }
catch (e) { if (e.response?.status === 400 && /UUID/.test(e.response?.data?.message ?? '')) { /* fix id source, do not retry blindly */ } } Prevention
- Keep resource ids from API responses only (GET /resources.json), never derive them
- Distinguish resource id vs secret id vs metadata id in your client model
- Validate path parameters with a UUID guard before requests
- Watch for URL encoders mangling ids
When it happens
Trigger: GET /secrets/resource/<id>.json with a non-UUID <id>: a resource name, numeric database key, URL-encoded garbage, or a truncated/typo'd id.
Common situations: Clients storing resource ids in the wrong column (e.g. slug); copy-paste losing characters; mixing up resource id with secret id; legacy code using incrementing ids.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- The request data is invalid: id invalid.
- The role identifier is not valid.
- Invalid id
- Please provide a valid request id.
- The authentication token id is invalid.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/d4343afa0115911e.
Report an issue: GitHub.
Appendix: source
Thrown at src/Controller/Secrets/SecretsViewController.php:73
$this->Resources = $this->fetchTable('Resources');
}
/**
* Secret View action
*
* @param string $resourceId uuid Identifier of the resource
* @throws \Cake\Http\Exception\BadRequestException if the resource id is not a uuid
* @throws \Cake\Http\Exception\NotFoundException if the user has no current READ access on the resource
* @throws \Cake\Http\Exception\NotFoundException if the user does not have a secret for the resource
* @return void
*/
public function view(string $resourceId)
{
$this->assertJson();
// Check request sanity
if (!Validation::uuid($resourceId)) {
throw new BadRequestException(__('The resource identifier should be a valid UUID.'));
}
$uac = $this->User->getAccessControl();
// Defence in depth: reject the read if the caller no longer has permission on the resource
$hasAccess = $this->Resources->Permissions->hasAccess(
PermissionsTable::RESOURCE_ACO,
$resourceId,
$uac->getId(),
Permission::READ
);
if (!$hasAccess) {
throw new NotFoundException(__('The secret does not exist.'));
}
// Retrieve the secret.
/** @var \App\Model\Entity\Secret $secret */
$secret = $this->Secrets->findByResourceUser($resourceId, $uac->getId())->first();View on GitHub (pinned to 31c1bbc10f)