{"record":{"id":"e253ffdb24abd8b4","repo":"ytti/oxidized","slug":"hook-jid-is-required","errorCode":null,"errorMessage":"hook.jid is required","messagePattern":"hook\\.jid is required","errorType":"validation","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"lib/oxidized/hook/xmppdiff.rb","lineNumber":44,"sourceCode":"\n        logger.info \"Joined #{cfg.channel}\"\n      end\n    rescue Timeout::Error\n      logger.info \"timed out\"\n      @client = nil\n      @muc = nil\n    end\n\n    @client.on_exception do\n      logger.info \"XMPP connection aborted, reconnecting\"\n      @client = nil\n      @muc = nil\n      connect\n    end\n  end\n\n  def validate_cfg!\n    raise KeyError, 'hook.jid is required' unless cfg.has_key?('jid')\n    raise KeyError, 'hook.password is required' unless cfg.has_key?('password')\n    raise KeyError, 'hook.channel is required' unless cfg.has_key?('channel')\n    raise KeyError, 'hook.nick is required' unless cfg.has_key?('nick')\n  end\n\n  def run_hook(ctx)\n    return unless ctx.node\n    return unless ctx.event.to_s == \"post_store\"\n\n    begin\n      Timeout.timeout(15) do\n        gitoutput = ctx.node.output.new\n        diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil\n\n        interesting = diff[:patch].lines.to_a[4..-1].any? do |line|\n          [\"+\", \"-\"].include?(line[0]) && (not [\"#\", \"!\"].include?(line[1]))\n        end\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/ytti/oxidized/blob/687ed4262d9d21e54662e872e2383386d8498f7b/lib/oxidized/hook/xmppdiff.rb#L26-L62","documentation":"The xmppdiff hook validates at startup that all four keys jid, password, channel and nick are present; the first missing one raises KeyError (lib/oxidized/hook/xmppdiff.rb:44). 'hook.jid is required' means the Jabber ID of the account oxidized logs in with is absent. The jid is passed to Jabber::Client.new(Jabber::JID.new(cfg.jid)) in connect and is the bare JID of that account, e.g. oxidized@xmpp.example.com.","triggerScenarios":"A hooks block with type: xmppdiff that omits jid: (typically only channel/nick were copied from an example), or a jid key lost to indentation or renaming (user/username).","commonSituations":"Copying a partial xmppdiff example; storing XMPP credentials outside the config and forgetting to template them in; editing the hooks block and breaking indentation.","solutions":["Add jid: oxidized@xmpp.example.com under the xmppdiff hook block","Also provide password, channel and nick: all four keys are required or the next validate_cfg! line raises the following KeyError","Restart oxidized and watch the log for hook validation"],"exampleFix":"# before\nhooks:\n  xmpp:\n    type: xmppdiff\n    channel: netdev@conference.example.com\n    nick: oxidized\n\n# after\nhooks:\n  xmpp:\n    type: xmppdiff\n    jid: oxidized@xmpp.example.com\n    password: secret\n    channel: netdev@conference.example.com\n    nick: oxidized","handlingStrategy":"validation","validationCode":"# check the xmppdiff block before oxidized loads it\nhook_cfg = YAML.load_file('/etc/oxidized/config')['hooks']['xmpp']\nmissing = %w[jid password channel nick].reject { |k| hook_cfg.key?(k) }\nraise ArgumentError, \"xmppdiff config missing: #{missing.join(', ')}\" unless missing.empty?","typeGuard":"def xmppdiff_cfg_valid?(cfg)\n  cfg.is_a?(Hash) && %w[jid password channel nick].all? { |k| cfg[k].is_a?(String) && !cfg[k].empty? }\nend","tryCatchPattern":"begin\n  hook.validate_cfg!\nrescue KeyError => e\n  abort \"fix the hooks config: #{e.message}\"\nend","preventionTips":["Use a dedicated XMPP account for oxidized; room occupants see its nick on every diff","Key-check all four xmppdiff keys in the config pipeline","Validate the JID format (local@domain) before deploy"],"tags":["oxidized","xmppdiff-hook","xmpp","jabber","config-validation","keyerror"],"backgroundTag":"missing-config-key","analyzedSha":"687ed4262d9d21e54662e872e2383386d8498f7b","analyzedAt":"2026-08-23T11:19:42.084Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}