Could not load a value as a module, because it is of type "option"

I am writing a module (my first one) to streamline/simplify the declaration of containers for my server.

The intended usage of the modules is this:

  imports = [ ./cont.nix ];
  hosting.Devops = {
    Gitea = { image = "gitea/gitea"; }; # Error is the same even with out this line (i.e. hosting.Devops = {};)
  };

This would create a container in the ‘Devops’ group named ‘Gitea’ using the image ‘gitea/gitea’.
The module transforms the input above to the format/layout expected in virtualisation.oci-containers.containers.

I declared options to fit/parse the above format/layout, they seem inline to the documenation/sources/guides i have seen, but might be the source of my problem.
I also wrote and tested (with nix repl) the expression to transform the above format to the format expected by virtualisation.oci-containers.containers and seems to work if i give the expression above in the repl.

When i try to actually nixos-rebuild with this module i get this error:
Could not load a value as a module, because it is of type "option", in file /etc/nixos/cont.nix.

I believe it is related to the cfg variable, but i don’t understand what is wrong and how to fix it.
I did not find anything on the internet, does anyone have any ideas?

Module cont.nix code

{ config, options, lib, pkgs, ... }:

with lib;
with builtins;
let
  cfg = config.hosting;

  containerOptions = { ... }: {
    image = mkOption {
      type = with types; uniq string;
      description = "Image to use for <name>";
    };

    volumes = mkOption {
      type = with types; listOf string;
      description = "Volume mounts for <name>";
      default = [];
    };
  };

  groupOptions = mkOption {
    type = types.attrsOf (types.submodule containerOptions);
  };

in {
  imports = [
  ];

  options.hosting = mkOption {
    default = {};
    type = types.attrsOf (types.submodule groupOptions);
    description = lib.mdDoc "Group of containers.";
  };

  config = {
    virtualisation.oci-containers.containers = mapAttrs (k: v: elemAt v 0) (zipAttrsWith (name: values: values) (attrValues (mapAttrs (gk: gv: (mapAttrs (ck: cv: cv // {group = gk;}) gv)) cfg)));
  };
}

Thanks for your time and ideas :wink:

Just a guess, but I’d look at this:

groupOptions is an option, and types.submodule expects an attribute set (or a function returning an attribute set, or a path to a file… but not an option).

I ended up rewriting everything, too many changes to mention …
One thing i was doing wrong was that all mkOptions in submodules have to reside inside a options set, like this:

test_submodule = { ... }: {
  options = {
    test_option = mkOption{
      type = bool;
    };
  };
}

Thanks for the feedback.