{"record":{"id":"b2f84fddf2bb9ada","repo":"apache/superset","slug":"report-schedule-id-name-r-has-no-resolvable","errorCode":null,"errorMessage":"Report schedule {id} ({name!r}) has no resolvable target (chart_id={chart_id}, dashboard_id={dashboard_id}); the report has neither a chart nor a dashboard.","messagePattern":"Report schedule (.+?) \\((.+?)\\) has no resolvable target \\(chart_id=(.+?), dashboard_id=(.+?)\\); the report has neither a chart nor a dashboard\\.","errorType":"exception","errorClass":"ReportScheduleUnexpectedError","httpStatus":500,"severity":"error","filePath":"superset/commands/report/execute.py","lineNumber":509,"sourceCode":"        # opaquely; raising here surfaces a clear, actionable error inside\n        # the state-machine envelope (ERROR log row + notification dispatch).\n        # Every content path (_get_screenshots, _get_csv_data,\n        # _get_embedded_data, _get_notification_content) funnels through this\n        # method, so this is the single choke point.\n        if chart is None and dashboard is None:\n            if self._report_schedule.chart_id is not None:\n                raise ReportScheduleTargetChartDeletedError()\n            # Symmetric guard for dashboard targets. Dashboard soft delete lands\n            # in the sibling rollout; until then this cannot fire (a dashboard\n            # with dependent reports cannot be deleted), which makes it inert\n            # rather than wrong — and it keeps the report-target error vocabulary\n            # parallel across entities from day one.\n            if self._report_schedule.dashboard_id is not None:\n                raise ReportScheduleTargetDashboardDeletedError()\n            # Defensive fallback for a malformed report with no target IDs.\n            # Missing relationships with a target ID are handled by the\n            # dedicated deleted-target errors above.\n            raise ReportScheduleUnexpectedError(\n                f\"Report schedule {self._report_schedule.id} \"\n                f\"({self._report_schedule.name!r}) has no resolvable target \"\n                f\"(chart_id={self._report_schedule.chart_id}, \"\n                f\"dashboard_id={self._report_schedule.dashboard_id}); \"\n                \"the report has neither a chart nor a dashboard.\"\n            )\n\n        force = \"true\" if self._report_schedule.force_screenshot else \"false\"\n        if chart:\n            if result_format in {\n                ChartDataResultFormat.CSV,\n                ChartDataResultFormat.XLSX,\n                ChartDataResultFormat.JSON,\n                ChartDataResultFormat.XLSX,\n            }:\n                return get_url_path(\n                    \"ChartDataRestApi.get_data\",\n                    pk=self._report_schedule.chart_id,","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/report/execute.py#L491-L527","documentation":"ReportScheduleUnexpectedError raised as a defensive fallback in _get_url when both chart and dashboard relationships are None AND neither chart_id nor dashboard_id is set — i.e. a malformed report row with no target at all. The message embeds the schedule id, name, and both null target ids so operators can identify the row directly.","triggerScenarios":"A report_schedule row manually inserted (or corrupted) with chart_id and dashboard_id both NULL; bugs in import/export flows that strip target ids; direct DB edits. Normal API paths cannot create a target-less report.","commonSituations":"Migrations or manual SQL backfills that leave nulls; a partially applied update that cleared the target column; test fixtures created without targets.","solutions":["Inspect the row named in the message: SELECT * FROM report_schedule WHERE id = <id>","Fix the row by setting a valid chart_id or dashboard_id, or delete the malformed schedule","If a custom tool created this row, fix the tool to always set exactly one target"],"exampleFix":"-- before: malformed row\nUPDATE report_schedule SET chart_id = NULL WHERE id = 42;  -- later execution fails\n\n-- after\nUPDATE report_schedule SET chart_id = 123 WHERE id = 42;  -- valid target","handlingStrategy":"validation","validationCode":"def report_has_target(report) -> bool:\n    return report.chart_id is not None or report.dashboard_id is not None","typeGuard":"def is_well_formed_report(report_schedule) -> bool:\n    \"\"\"A report must carry exactly one non-null target id.\"\"\"\n    return (report_schedule.chart_id is not None) ^ (report_schedule.dashboard_id is not None)","tryCatchPattern":"try:\n    _get_url()\nexcept ReportScheduleUnexpectedError as ex:\n    if 'no resolvable target' in str(ex):\n        # quarantine the malformed row named in the message\n        flag_for_repair(report_schedule.id)","preventionTips":["Never insert report_schedule rows by hand without exactly one target id","Add a DB constraint or CI check that chart_id/dashboard_id are not both null","Use the API for all report creation so validation always runs"],"tags":["alerts-reports","data-integrity","execution"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}