Skip to content

Fix 9893#10467

Open
prathamesh-patil-5090 wants to merge 26 commits intocvat-ai:developfrom
prathamesh-patil-5090:fix-9893
Open

Fix 9893#10467
prathamesh-patil-5090 wants to merge 26 commits intocvat-ai:developfrom
prathamesh-patil-5090:fix-9893

Conversation

@prathamesh-patil-5090
Copy link
Copy Markdown
Contributor

Fix API 500 error on /api/jobs/{id}/data/meta

Description

This PR resolves an issue where requesting the /api/jobs/{id}/data/meta endpoint via the Django REST Framework Browsable API resulted in a 500 Internal Server Error (AttributeError: 'Data' object has no attribute 'organization_id').

Root Cause:
When loading the browsable API UI, DRF attempts to render an HTML form for PATCH requests and automatically invokes check_object_permissions on the Data instance associated with the view. The CVAT IAM permission flow looks for obj.organization_id, but the Data model lacked this attribute.

Fix:
Added organization and organization_id as properties on the Data model. The properties lazily evaluate and delegate to the model's related parent Task.

How to manually test it

  1. Start your local CVAT development server.
  2. Log into the application and ensure you have a project/task created containing at least one image. Note the ID of the created Job (e.g., Job ID 3).
  3. Send a GET request to http://localhost:7000/api/jobs/3/data/meta. You can do this by:
    • Opening the URL directly in your web browser (which uses the DRF Browsable API).
    • Using an API testing client like Postman.
  4. Confirm that the endpoint successfully returns a 200 OK status code along with the expected metadata JSON payload, and no 500 traceback is thrown in the console.

Screenshots

Here is a test confirming the endpoint now returns the proper 200 OK response payload without failing on permission checks:

Screenshot from 2026-04-12 19-30-43

Closes #9893

prathamesh-patil-5090 and others added 26 commits November 23, 2025 15:36
Refactor not found components to use a common handleReturn function for navigation.
Remove console log for history length in TaskNotFoundComponent.
Added a new 'Return to Previous Page' button with smart fallback navigation.
Updated link for 'Return to Previous Page' button feature.
Updated the link for the 'Return to Previous Page' button in the changelog.
Adds organization and organization_id properties to the Data model to resolve AttributeError during permissions checks in DRF browsable API.
Copilot AI review requested due to automatic review settings April 12, 2026 14:03
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a Django REST Framework Browsable API 500 on GET /api/jobs/{id}/data/meta by ensuring IAM permission checks can resolve an organization from a Data instance.

Changes:

  • Added organization and organization_id properties to Data (delegating to the related Task).
  • Added a changelog fragment documenting the fix.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
cvat/apps/engine/models.py Adds Data.organization / Data.organization_id to support IAM permission resolution in browsable API flows.
changelog.d/20260412_133400_aramesh_fix_data_organization_id.md Documents the fixed 500 error in the changelog fragments.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +469 to +480
def organization(self):
try:
return self.tasks.first().organization
except AttributeError:
return None

@property
def organization_id(self):
try:
return self.tasks.first().organization_id
except AttributeError:
return None
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The organization property is using a broad try/except AttributeError as control flow. This will also mask unrelated AttributeErrors (e.g., if something inside the accessed attributes changes) and makes debugging harder. Consider explicitly handling the “no related task” case (and optionally the “unsaved Data instance” case) and adding a return type annotation for consistency with other organization(_id) properties in this module (e.g., Job.organization_id).

Suggested change
def organization(self):
try:
return self.tasks.first().organization
except AttributeError:
return None
@property
def organization_id(self):
try:
return self.tasks.first().organization_id
except AttributeError:
return None
def organization(self) -> Organization | None:
task = self.tasks.first()
if task is None:
return None
return task.organization
@property
def organization_id(self) -> int | None:
task = self.tasks.first()
if task is None:
return None
return task.organization_id

Copilot uses AI. Check for mistakes.
Comment on lines +468 to +480
@property
def organization(self):
try:
return self.tasks.first().organization
except AttributeError:
return None

@property
def organization_id(self):
try:
return self.tasks.first().organization_id
except AttributeError:
return None
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

organization_id currently calls self.tasks.first() on every access and relies on catching AttributeError for the empty-related-set case. It would be more robust to explicitly check for a related task (and potentially cache the resolved org/org_id for the lifetime of the model instance) to avoid repeated queries and to avoid swallowing unexpected AttributeErrors.

Suggested change
@property
def organization(self):
try:
return self.tasks.first().organization
except AttributeError:
return None
@property
def organization_id(self):
try:
return self.tasks.first().organization_id
except AttributeError:
return None
def _get_first_task_for_organization(self):
if not hasattr(self, "_first_task_for_organization_cache"):
self._first_task_for_organization_cache = self.tasks.first()
return self._first_task_for_organization_cache
@property
def organization(self):
task = self._get_first_task_for_organization()
return task.organization if task is not None else None
@property
def organization_id(self):
task = self._get_first_task_for_organization()
return task.organization_id if task is not None else None

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,2 @@
### Fixed
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changelog fragments in changelog.d/ consistently include a blank line after the section header (e.g., other recent fragments use ### Fixed followed by an empty line, then the bullet). Add the missing blank line here to match the established formatting (and keep the fragment consistent with tooling that may expect that structure).

Suggested change
### Fixed
### Fixed

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API 500 Resp - Unable to get metainformation for media files in a job

3 participants