passbolt/passbolt_api · error · BadRequestException

The identifier should be a valid UUID.

Error message

The identifier should be a valid UUID.

What it means

Passbolt throws this 400 when the acoForeignKey path parameter of the permissions view endpoint is not a valid UUID. PermissionsViewController::viewAcoPermissions validates with Validation::uuid() before any lookup.

Solutions

  1. Ensure the path parameter is the resource's UUID obtained from GET /resources.json
  2. Add client-side UUID validation before the request
  3. Fix URL construction to interpolate the id field, not name or legacy numeric id
  4. Check logs/proxies for id truncation if the id looks correct in code

Example fix

// before
const url = `/permissions/resource/${resource.slug}.json`;
// after
if (!isUuid(resource.id)) throw new Error('expected resource UUID');
const url = `/permissions/resource/${resource.id}.json`;
Defensive patterns

Strategy: validation

Validate before calling

const isUuid = (v) => 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);
if (!isUuid(resourceId)) throw new Error('acoForeignKey must be a resource UUID');

Type guard

const asResourceId = (r) => isUuid(r?.id) ? r.id : null;

Try / catch

if (!isUuid(id)) id = await resolveResourceId(resource);

Prevention

When it happens

Trigger: GET /permissions/resource/<acoForeignKey>.json with a non-UUID identifier: numeric id, slug, empty string, or an id that got mangled/truncated in transit.

Common situations: Legacy integrations using integer resource ids; concatenating the wrong variable into the URL; a client parsing a display name instead of the id; URL encoding issues dropping characters.

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


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/ef3815553833feed. Report an issue: GitHub.

Appendix: source

Thrown at src/Controller/Permissions/PermissionsViewController.php:69

    /**
     * View permissions defined for an aco instance.
     * Only support the entity Resource for now.
     *
     * @param string $acoForeignKey The target aco id.
     * @throws \Cake\Http\Exception\BadRequestException If the parameter acoForeignKey is null
     * @throws \Cake\Http\Exception\BadRequestException If the parameter acoForeignKey is not a valid uuid
     * @throws \Cake\Http\Exception\NotFoundException If the target resource doesn't exist
     * @throws \Cake\Http\Exception\NotFoundException If the target resource is soft deleted
     * @return void
     */
    public function viewAcoPermissions(string $acoForeignKey)
    {
        $this->assertJson();

        // Check request sanity
        if (!Validation::uuid($acoForeignKey)) {
            throw new BadRequestException(__('The identifier should be a valid UUID.'));
        }

        // Retrieve and sanity the query options.
        $whitelist = ['contain' => ['group', 'user', 'user.profile']];
        $options = $this->QueryString->get($whitelist);

        // Check that the user has access to the resource.
        $resource = $this->Resources->findView($this->User->id(), $acoForeignKey)->first();
        if (empty($resource)) {
            throw new NotFoundException(__('The resource does not exist.'));
        }

        // Retrieve the permissions.
        $permissions = $this->Permissions->findViewAcoPermissions($acoForeignKey, $options);
        $this->success(__('The operation was successful.'), $permissions);
    }
}

View on GitHub (pinned to 31c1bbc10f)