{"record":{"id":"f7cbe4d3108ce574","repo":"instructure/canvas-lms","slug":"a-new-integration-id-data-change-new-integration-id","errorCode":null,"errorMessage":"A new_integration_id, '#{data_change.new_integration_id}', referenced an existing #{type} and the #{type} with integration_id '#{data_change.old_integration_id}' was not updated","messagePattern":"A new_integration_id, '#(.+?)', referenced an existing #(.+?) and the #(.+?) with integration_id '#(.+?)' was not updated","errorType":"exception","errorClass":"ImportError","httpStatus":null,"severity":"error","filePath":"lib/sis/change_sis_id_importer.rb","lineNumber":131,"sourceCode":"        if data_change.new_integration_id.present?\n          updates[\"integration_id\"] = data_change.new_integration_id\n          if data_change.new_integration_id == \"<delete>\"\n            updates[\"integration_id\"] = nil\n          end\n        end\n        updates\n      end\n\n      def check_for_conflicting_ids(column, details, type, data_change)\n        if type == \"group_category\" && (data_change.old_integration_id || data_change.new_integration_id)\n          raise ImportError, \"Group categories should not have integration IDs.\"\n        end\n\n        check_new = details[:scope].where(column => data_change.new_id).exists? if data_change.new_id.present?\n        raise ImportError, \"A new_id, '#{data_change.new_id}', referenced an existing #{type} and the #{type} with #{column} '#{data_change.old_id}' was not updated\" if check_new\n\n        check_int = details[:scope].where(integration_id: data_change.new_integration_id).exists? if data_change.new_integration_id.present?\n        raise ImportError, \"A new_integration_id, '#{data_change.new_integration_id}', referenced an existing #{type} and the #{type} with integration_id '#{data_change.old_integration_id}' was not updated\" if check_int\n      end\n\n      def find_item_to_update(column, details, type, data_change)\n        if data_change.old_id.present?\n          old_item = details[:scope].find_by(column => data_change.old_id)\n        end\n        if data_change.old_integration_id.present?\n          old_int_item = details[:scope].find_by(integration_id: data_change.old_integration_id)\n        end\n        if data_change.old_id.present? && data_change.old_integration_id.present?\n          raise ImportError, \"An old_id, '#{data_change.old_id}', referenced a different #{type} than the old_integration_id, '#{data_change.old_integration_id}'\" unless old_item == old_int_item\n\n          return old_item\n        end\n        if data_change.old_id.present? && data_change.old_integration_id.blank?\n          raise ImportError, \"An old_id, '#{data_change.old_id}', referenced a non-existent #{type} and was not changed.\" unless old_item\n\n          return old_item","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/sis/change_sis_id_importer.rb#L113-L149","documentation":"check_for_conflicting_ids raises this when a non-blank new_integration_id already exists on another record of the type being changed (scope.where(integration_id: new_integration_id).exists?). Integration ids must remain unique within the account, so assigning an already-used one is rejected and no update occurs.","triggerScenarios":"change_sis_id row where new_integration_id matches an existing row's integration_id — e.g. moving an integration_id from record X to record Y while X still holds it, or replaying a previously applied change.","commonSituations":"Two SIS systems writing the same integration_id, idempotent re-imports, or re-pointing an integration id during a migration without clearing it from the source record first.","solutions":["Clear the integration_id on the conflicting record first (new_integration_id '<delete>' on that record), then assign it.","Query scope.where(integration_id: new_integration_id).exists? before submitting to detect the holder.","Deduplicate rows in the importing system to avoid replays."],"exampleFix":"// before\ncourse,C1,C2,,INT-DUP\n// after: free INT-DUP first\ncourse,C-SRC,,,<delete>\ncourse,C1,C2,,INT-DUP","handlingStrategy":"validation","validationCode":"if dc.new_integration_id.present? &&\n   scope_for(dc.type).where(integration_id: dc.new_integration_id).exists?\n  raise ArgumentError, 'new_integration_id already in use'\nend\nprocess_change_sis_id(dc)","typeGuard":null,"tryCatchPattern":"begin\n  process_change_sis_id(dc)\nrescue SIS::ImportError => e\n  logger.warn(\"integration_id collision: #{e.message}\")\nend","preventionTips":["Reserve integration_ids centrally so two systems cannot allocate the same one.","Free an integration_id with new_integration_id '<delete>' before reassigning it.","Detect replays by tracking applied change rows."],"tags":["sis","ruby","import","uniqueness","conflict"],"backgroundTag":"duplicate-identifier-conflict","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}