Area: Product
Sub-Area: Ownership Management
Issue
When a user who is assigned as an owner of datasets is deleted from the DataHub system, the ownership assignment persists on the datasets. The deleted user's profile is removed, but their ownership reference remains attached to assets, creating orphaned ownership entries that can confuse other users and impact governance reporting.
You Might Be Asking:
- Is it expected behavior that ownership persists after user deletion?
- How do I clean up orphaned ownership references?
- Should ownership be automatically removed when a user is deleted?
- How can I prevent this issue?
Solution
Ownership persistence after user deletion is expected behavior by design. DataHub maintains ownership history and does not automatically remove ownership assignments when users are deleted.
Why Ownership Persists:
- Historical Record: Maintains audit trail of who owned assets
- Data Integrity: Preserves ownership history for compliance
- Prevents Data Loss: Avoids accidental removal of important ownership information
- Intentional Design: Deletion and ownership cleanup are separate operations
Recommended Approaches:
Option 1: Reassign Ownership Before User Deletion
Best practice is to reassign ownership before removing users:
from datahub.emitter.rest_emitter import DatahubRestEmitter
from datahub.metadata.schema_classes import OwnerClass, OwnershipClass, OwnershipTypeClass
def reassign_user_ownership(old_user_urn, new_user_urn, datahub_url, token):
"""Reassign all ownership from one user to another"""
emitter = DatahubRestEmitter(gms_server=datahub_url, token=token)
# Query for all assets owned by the user
# (Using search API or GraphQL)
query = f"""
query {{
search(
input: {{
type: DATASET,
query: "*",
filters: {{
field: "owners",
value: "{old_user_urn}"
}}
}}
) {{
searchResults {{
entity {{
urn
}}
}}
}}
}}
"""
# For each asset, update ownership
# ... implementation logic
Option 2: Bulk Remove Orphaned Ownership
Use GraphQL to remove ownership references after user deletion:
# Remove specific owner from a dataset
mutation {
removeOwner(
input: {
ownerUrn: "urn:li:corpuser:deleted_user",
resourceUrn: "urn:li:dataset:(urn:li:dataPlatform:snowflake,db.schema.table,PROD)"
}
)
}
Option 3: Automated Cleanup Script
Create a maintenance script to identify and clean orphaned ownership:
from datahub.emitter.rest_emitter import DatahubRestEmitter
import requests
def find_orphaned_ownership(datahub_url, token):
"""Find datasets with deleted user ownership"""
# Get all users
headers = {"Authorization": f"Bearer {token}"}
users_response = requests.post(
f"{datahub_url}/api/graphql",
json={
"query": """
query {
listUsers(input: {start: 0, count: 1000}) {
users {
urn
username
}
}
}
"""
},
headers=headers
)
active_users = {u['urn'] for u in users_response.json()['data']['listUsers']['users']}
# Get all ownership assignments
# Compare against active users
# Return orphaned ownership URNs
return orphaned_assignments
def cleanup_orphaned_ownership(orphaned_list, datahub_url, token):
"""Remove ownership for deleted users"""
emitter = DatahubRestEmitter(gms_server=datahub_url, token=token)
for dataset_urn, owner_urn in orphaned_list:
# Remove owner using SDK
pass
Option 4: Prevent User Deletion
Instead of deleting users, consider marking them inactive:
# Suspend user instead of deleting
mutation {
updateCorpUserProperties(
urn: "urn:li:corpuser:departing_user",
input: {
active: false,
fullName: "Departing User (Inactive)"
}
)
}
Bulk Ownership Transfer Script:
# bulk_transfer_ownership.py
from datahub.emitter.mce_builder import make_user_urn, make_dataset_urn
from datahub.emitter.rest_emitter import DatahubRestEmitter
from datahub.metadata.schema_classes import OwnershipClass, OwnerClass, OwnershipTypeClass
def transfer_ownership(
from_user: str,
to_user: str,
dataset_patterns: list,
datahub_url: str,
token: str
):
"""Transfer ownership from one user to another for matching datasets"""
emitter = DatahubRestEmitter(gms_server=datahub_url, token=token)
from_urn = make_user_urn(from_user)
to_urn = make_user_urn(to_user)
# Search for datasets owned by from_user
# For each dataset:
# 1. Remove from_user ownership
# 2. Add to_user ownership
# 3. Preserve ownership type (TECHNICAL_OWNER, BUSINESS_OWNER, etc.)
print(f"Transferred ownership from {from_user} to {to_user}")
# Usage
if __name__ == "__main__":
transfer_ownership(
from_user="john.doe",
to_user="jane.smith",
dataset_patterns=["snowflake.*"],
datahub_url="https://your-instance.acryl.io",
token="your-token"
)
Best Practices:
- Offboarding Process: Include ownership reassignment in user offboarding workflows
- Regular Audits: Periodically review ownership for deleted users
- Group Ownership: Use groups instead of individuals when possible to avoid this issue
- Documentation: Document ownership transfer procedures
- Automation: Integrate ownership transfer with HR/identity management systems
Additional Notes
- This behavior is consistent across entity types (datasets, dashboards, charts)
- Group ownership does not have this issue when members are removed
- Some organizations prefer to keep historical ownership for compliance
- Consider your organization's requirements before implementing automatic cleanup
Related Documentation
Related Tickets
- 5040
Tags: ownership, user-deletion, orphaned-ownership, user-management, governance, cleanup, data-stewardship