{"record":{"id":"900b567a3dc76024","repo":"Freika/dawarich","slug":"failed-to-read-json-data-message","errorCode":null,"errorMessage":"Failed to read JSON data: %{message}","messagePattern":"Failed to read JSON data: %(.+?)","errorType":"exception","errorClass":"StandardError","httpStatus":null,"severity":"error","filePath":"app/services/users/import_data/v1_handler.rb","lineNumber":57,"sourceCode":"    Rails.logger.info \"Processing v1 format archive for user: #{user.email}\"\n\n    json_path = import_directory.join('data.json')\n    raise StandardError, I18n.t('services.users.import_data.v1_handler.data_file_missing') unless File.exist?(json_path)\n\n    initialize_stream_state\n\n    handler = ::JsonStreamHandler.new(self)\n    parser = Oj::Parser.new(:saj, handler: handler)\n\n    File.open(json_path, 'rb') do |io|\n      parser.load(io)\n    end\n\n    finalize_stream_processing\n  rescue Oj::ParseError => e\n    raise StandardError, I18n.t('services.users.import_data.v1_handler.invalid_json', message: e.message)\n  rescue IOError => e\n    raise StandardError, I18n.t('services.users.import_data.v1_handler.read_failed', message: e.message)\n  end\n\n  attr_reader :expected_counts\n\n  # Called by JsonStreamHandler for non-streamed sections\n  def handle_section(key, value)\n    case key\n    when 'counts'\n      @expected_counts = value if value.is_a?(Hash)\n      Rails.logger.info \"Expected entity counts from export: #{@expected_counts}\" if @expected_counts\n    when 'settings'\n      import_settings(value) if value.present?\n    when 'areas'\n      import_areas(value)\n    when 'imports'\n      import_imports(value)\n    when 'exports'\n      import_exports(value)","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/Freika/dawarich/blob/97fad417c5a11b0eb11157890635e015723a2e97/app/services/users/import_data/v1_handler.rb#L39-L75","documentation":"StandardError raised from V1Handler#process's `rescue IOError`: reading data.json (File.open + parser.load streaming) failed at the IO layer rather than the parsing layer - the stream could not be read. The IOError's message is interpolated into 'Failed to read JSON data: %{message}'. This is an infrastructure error (file gone, permissions, fd closed, disk/full filesystem fault), distinct from error 51 which is document syntax.","triggerScenarios":"The extracted data.json deleted or its permissions changed while the import runs, a file descriptor closed underneath the parser, or a filesystem-level fault (disk full, NFS hiccup, ephemeral container tmp mount) during the streamed read of a multi-gigabyte export.","commonSituations":"tmp/ cleanup jobs racing the import, containerized deployments with small or volatile tmpfs mounts, storage pressure during large restores.","solutions":["Check the interpolated IO message plus the filesystem: free space and permissions of the tmp/import_* directory","Ensure nothing prunes Rails.root/tmp while imports run (systemd-tmpfiles, cron cleaners)","Retry the import - transient IO faults are the usual cause and the transaction rolls back cleanly","Give the import directory more durable storage if tmpfs is too small for the export"],"exampleFix":"# before: import runs from tmpfs that can drop files mid-read\n@import_directory = Rails.root.join('tmp', \"import_#{user.email}_#{Time.current.to_i}\")\n\n# after: point large imports at durable storage with room\nIMPORT_ROOT = ENV.fetch('DAWARICH_IMPORT_DIR') { Rails.root.join('tmp') }\n@import_directory = Pathname.new(IMPORT_ROOT).join(\"import_#{user.id}_#{Time.current.to_i}\")","handlingStrategy":"retry","validationCode":"path = import_directory.join('data.json')\nraise ArgumentError, 'data.json unreadable' unless path.readable?","typeGuard":"def readable_data_file?(import_directory)\n  p = import_directory.join('data.json')\n  p.exist? && p.readable?\nend","tryCatchPattern":"begin\n  Users::ImportData::V1Handler.new(user, dir, stats).process\nrescue StandardError => e\n  if e.message.start_with?('Failed to read JSON data')\n    retry if (attempts += 1) < 3   # IO faults are usually transient\n  else\n    raise\n  end\nend","preventionTips":["Give tmp/ durable storage and headroom for multi-GB exports","Exclude import tmp dirs from tmpwatchers/cleaners","Monitor disk space before starting user-data restores"],"tags":["import","io","file-read","streaming","user-data-restore"],"backgroundTag":"file-read-failed","analyzedSha":"97fad417c5a11b0eb11157890635e015723a2e97","analyzedAt":"2026-08-21T17:04:17.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}