Adding Admin Permissions via Direct SQL in Self-Hosted LangSmith

Last updated: February 2, 2026

Problem

In self-hosted LangSmith deployments, administrators may need to grant organization admin access to users for organizations where they don't currently have permissions. This cannot be done through the UI when the admin lacks access to that specific organization.

Solution

Use direct SQL queries to add organization and workspace admin permissions. This is a two-step process - you must create both organization-level AND workspace-level identity records.

Step 1: Add Organization Admin Identity

First, check if the user already has an organization-level identity:

SELECT i.id as identity_id, 
       i.ls_user_id, 
       i.organization_id, 
       u.email,
       r.name as current_role
FROM identities i
JOIN users u ON i.ls_user_id = u.ls_user_id
LEFT JOIN roles r ON i.role_id = r.id
WHERE u.email = '<user_email>'
  AND i.access_scope = 'organization';

If the user already exists in the org, update their role:

UPDATE identities
SET role_id = (
    SELECT id 
    FROM roles 
    WHERE name = 'ORGANIZATION_ADMIN' 
      AND access_scope = 'organization'
),
read_only = false
WHERE organization_id = '<org_id>'
  AND ls_user_id = '<ls_user_id>'
  AND access_scope = 'organization';

If the user doesn't exist in the org, insert a new identity record. The id field will auto-generate.

Step 2: Add Workspace Admin Identities

After adding the organization identity, you must also create workspace-level admin identities. Without this step, the user will see the org in the UI but encounter permission errors when switching to it.

First, get the required values:

SELECT 
    i.id as org_identity_id,
    i.organization_id,
    i.user_id,
    i.ls_user_id
FROM identities i
WHERE i.access_scope = 'organization'
  AND i.organization_id = '<org_id>';

Then insert workspace admin identities for all tenants in the organization:

INSERT INTO identities (tenant_id, organization_id, user_id, read_only, role_id, access_scope, parent_identity_id, ls_user_id)
SELECT
    t.id,
    '<org_id>',
    '<user_id>',
    false,
    (SELECT id FROM roles WHERE name = 'WORKSPACE_ADMIN' AND access_scope = 'workspace'),
    'workspace',
    '<org_identity_id>',
    '<ls_user_id>'
FROM tenants t
WHERE t.organization_id = '<org_id>'
ON CONFLICT (tenant_id, ls_user_id) WHERE access_scope = 'workspace'
DO UPDATE SET
    role_id = EXCLUDED.role_id,
    read_only = EXCLUDED.read_only;

Key Points

  • Both steps are required - Creating only the organization identity will cause the UI to crash with permission errors when switching to that org

  • The id field auto-generates - No need to manually specify it when inserting

  • The parent_identity_id links records - Workspace identities must reference their parent organization identity

  • Use ON CONFLICT for safety - This handles cases where workspace identities may already exist