{"record":{"id":"eff36baf717ad69e","repo":"bytebase/bytebase","slug":"found-v-tasks-with-id-v","errorCode":null,"errorMessage":"found %v tasks with id %v","messagePattern":"found (.+?) tasks with id (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/store/task.go","lineNumber":93,"sourceCode":"// TaskStatusCount holds aggregated task counts grouped by plan, environment and API-visible status.\ntype TaskStatusCount struct {\n\tProjectID   string\n\tPlanID      int64\n\tEnvironment string\n\tStatus      string\n\tCount       int32\n}\n\n// GetTaskByID gets a task by ID.\nfunc (s *Store) GetTaskByID(ctx context.Context, projectID string, id int64) (*TaskMessage, error) {\n\ttasks, err := s.ListTasks(ctx, &TaskFind{ProjectID: projectID, ID: &id})\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed to get Task with ID %d\", id)\n\t}\n\tif len(tasks) == 0 {\n\t\treturn nil, nil\n\t} else if len(tasks) > 1 {\n\t\treturn nil, errors.Errorf(\"found %v tasks with id %v\", len(tasks), id)\n\t}\n\treturn tasks[0], nil\n}\n\n// Get a blocking task in the pipeline.\n// A task is blocked by a task with a smaller schema version within the same pipeline.\nfunc (s *Store) FindBlockingTaskByVersion(ctx context.Context, projectID string, planUID int64, instanceID, databaseName string, version string) (*int64, error) {\n\tmyVersion, err := model.NewVersion(version)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tq := qb.Q().Space(`\n\t\tSELECT\n\t\t\ttask.id,\n\t\t\ttask.payload->>'schemaVersion'\n\t\tFROM task\n\t\tLEFT JOIN plan ON plan.project = task.project AND plan.id = task.plan_id\n\t\tLEFT JOIN issue ON issue.project = plan.project AND issue.plan_id = plan.id","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/store/task.go#L75-L111","documentation":"GetTaskByID expects at most one task per (projectID, id); if ListTasks returns more than one it raises errors.Errorf \"found %v tasks with id %v\". This is an internal invariant violation: a project-scoped task ID must be unique, so duplicates indicate data corruption or a query that isn't filtering by project correctly.","triggerScenarios":"The task table contains duplicate rows with the same ID within a project (should be impossible with a proper primary key), or the ProjectID filter is not applied so tasks from other projects match the ID.","commonSituations":"Restored/merged metadata databases with inconsistent task rows; code changes that drop the ProjectID predicate from TaskFind; cross-project ID reuse assumptions.","solutions":["Query the task table for the duplicate: SELECT id, project FROM task WHERE id = <id>; remove or fix the offending duplicate rows.","Confirm TaskFind is passing ProjectID so the query scopes by project.","Check task table primary key/constraints in LATEST.sql against the live metadata DB — duplicates imply missing constraints from an unmigrated or altered DB."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var n int\n_ = db.QueryRow(`SELECT COUNT(*) FROM task WHERE id = $1`, id).Scan(&n)\n// n > 1 means corrupted data: dedupe before calling GetTaskByID","typeGuard":null,"tryCatchPattern":"task, err := store.GetTaskByID(ctx, projectID, id)\nif err != nil {\n\tif strings.Contains(err.Error(), \"found \") && strings.Contains(err.Error(), \"tasks with id\") {\n\t\t// dedupe task rows; don't retry — data corruption won't self-heal\n\t}\n\treturn err\n}","preventionTips":["Never drop or alter the task table's primary key.","Always scope task lookups by ProjectID.","After restoring/merging metadata databases, run integrity checks for duplicate IDs."],"tags":["database","task","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}