{"record":{"id":"deee2182450e1614","repo":"lima-vm/lima","slug":"c-paths-socketvmnet-is-empty","errorCode":null,"errorMessage":"c.Paths.SocketVMNet is empty","messagePattern":"c\\.Paths\\.SocketVMNet is empty","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/networks/commands.go","lineNumber":107,"sourceCode":"\t\treturn osutil.LookupUser(\"root\")\n\t}\n\treturn osutil.User{}, fmt.Errorf(\"daemon %#q not defined\", daemon)\n}\n\nfunc (c *Config) MkdirCmd() string {\n\treturn fmt.Sprintf(\"/bin/mkdir -m 775 -p %s\", c.Paths.VarRun)\n}\n\nfunc (c *Config) StartCmd(name, daemon string) string {\n\tif ok, _ := c.IsDaemonInstalled(daemon); !ok {\n\t\tpanic(fmt.Errorf(\"daemon %#q is not available\", daemon))\n\t}\n\tvar cmd string\n\tswitch daemon {\n\tcase SocketVMNet:\n\t\tnw := c.Networks[name]\n\t\tif c.Paths.SocketVMNet == \"\" {\n\t\t\tpanic(\"c.Paths.SocketVMNet is empty\")\n\t\t}\n\t\tcmd = fmt.Sprintf(\"%s --pidfile=%s --socket-group=%s --vmnet-mode=%s\",\n\t\t\tc.Paths.SocketVMNet, c.PIDFile(name, SocketVMNet), c.Group, nw.Mode)\n\t\tswitch nw.Mode {\n\t\tcase ModeBridged:\n\t\t\tcmd += fmt.Sprintf(\" --vmnet-interface=%s\", nw.Interface)\n\t\tcase ModeHost, ModeShared:\n\t\t\tcmd += fmt.Sprintf(\" --vmnet-gateway=%s --vmnet-dhcp-end=%s --vmnet-mask=%s\",\n\t\t\t\tnw.Gateway, nw.DHCPEnd, nw.NetMask)\n\t\t}\n\t\tcmd += \" \" + c.Sock(name)\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unexpected daemon %#q\", daemon))\n\t}\n\treturn cmd\n}\n\nfunc (c *Config) StopCmd(name, daemon string) string {","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/lima-vm/lima/blob/dd909d0973cd84fa35f9e1693181b4585ea616c1/pkg/networks/commands.go#L89-L125","documentation":"Within StartCmd's SocketVMNet branch, the code re-checks that c.Paths.SocketVMNet is non-empty before formatting the command, panicking with 'c.Paths.SocketVMNet is empty' if it is. This is a defense-in-depth assertion: normally IsDaemonInstalled would have panicked earlier, so reaching here implies an inconsistent config state (e.g. IsDaemonInstalled behavior changed or config mutated between calls).","triggerScenarios":"StartCmd is called on a Config whose Paths.SocketVMNet field is the empty string but which somehow passed the earlier IsDaemonInstalled check — i.e. config mutated concurrently or constructed inconsistently.","commonSituations":"Programmatically built Config structs that bypass networks.yaml validation; race where the config is reloaded between the check and command construction; hand-assembled Config in tests.","solutions":["Ensure Paths.SocketVMNet is populated from networks.yaml before building a Config programmatically","Do not mutate Config fields after validation; treat Config as read-only","Construct the config via the normal loader so paths are validated once"],"exampleFix":"// before\ncfg := &networks.Config{} // SocketVMNet path empty\npanicCmd := cfg.StartCmd(\"shared\", networks.SocketVMNet)\n// after\ncfg, err := networks.LoadConfig() // populates Paths.SocketVMNet from networks.yaml","handlingStrategy":"validation","validationCode":"if cfg.Paths.SocketVMNet == \"\" {\n    return fmt.Errorf(\"config invalid: paths.socketVMNet must be set\")\n}","typeGuard":null,"tryCatchPattern":"func safeStartCmd(cfg *networks.Config, name, daemon string) (cmd string, err error) {\n    defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"%v\", r) } }()\n    return cfg.StartCmd(name, daemon), nil\n}","preventionTips":["Load Config via the standard loader, never hand-assemble the struct","Treat Config as immutable after load; reload rather than mutate","Keep Paths.SocketVMNet set consistently — both panic guards depend on it"],"tags":["network","daemon","panic","config","go"],"backgroundTag":"missing-config-path","analyzedSha":"dd909d0973cd84fa35f9e1693181b4585ea616c1","analyzedAt":"2026-09-01T14:24:59.842Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}