diff --git a/gui/backend.go b/gui/backend.go
index edb2b173a116c0ad3ad2eaf50910869a774b25e3..92cda6e28cc69daccaa523afa1e246b0baec7628 100644
--- a/gui/backend.go
+++ b/gui/backend.go
@@ -30,7 +30,6 @@ func Unblock() {
 //export Quit
 func Quit() {
 	backend.Quit()
-
 }
 
 //export DonateAccepted
diff --git a/gui/main.cpp b/gui/main.cpp
index eca834a90b4b927215e6e37a0daa809064e28d08..670e66495e1782a53cebfdca1e22a136b03b0c4b 100644
--- a/gui/main.cpp
+++ b/gui/main.cpp
@@ -34,7 +34,7 @@ std::string getEnv(std::string const& key)
     return val == NULL ? std::string() : std::string(val);
 }
 
-void signalHandler(int signum) {
+void signalHandler(int) {
     Quit();
     exit(0);
 }
diff --git a/gui/qml/main.qml b/gui/qml/main.qml
index 8d756c6c149421454caa342dc6227300022635d0..efcfef216880fb99753ea3cea6075a5223701212 100644
--- a/gui/qml/main.qml
+++ b/gui/qml/main.qml
@@ -11,7 +11,6 @@ ApplicationWindow {
 
     property var     ctx
 
-
     Connections {
         target: jsonModel
         onDataChanged: {
@@ -20,9 +19,24 @@ ApplicationWindow {
                 console.debug(jsonModel.getJson())
                 donate.visible = true
             }
+            if (ctx.errors ) {
+               // TODO consider disabling on/off buttons, or quit after closing the dialog
+               if ( ctx.errors  == "nohelpers" ) {
+                   showInitFailure(qsTr("Could not find helpers. Check your installation"))
+               } else if ( ctx.errors == "nopolkit" ) {
+                   showInitFailure(qsTr("Could not find polkit agent."))
+               } else {
+                   console.debug(ctx.errors)
+               }
+            }
         }
     }
 
+    function showInitFailure(msg) {
+          initFailure.text = msg
+          initFailure.visible  = true
+    }
+
     Component.onCompleted: {
         /* stupid as it sounds, windows doesn't like to have the systray icon
          not being attached to an actual application window.
@@ -210,9 +224,6 @@ ApplicationWindow {
         text: ""
         detailedText: ""
         visible: false
-        //text: ctx ? qsTr("Can't connect to %1").arg(ctx.appName) : ""
-        //detailedText: ctx ? ctx.errorStartingMsg : ""
-        //visible: ctx.errorStartingMsg != ""
     }
 
     MessageDialog {
@@ -222,7 +233,6 @@ ApplicationWindow {
         title: qsTr("Missing authentication agent")
         text: qsTr("Could not find a polkit authentication agent. Please run one and try again.")
         visible: false
-        //visible: ctx.missingAuthAgent == "true"
     }
 
     MessageDialog {
@@ -232,7 +242,5 @@ ApplicationWindow {
         title: qsTr("Initialization Error")
         text: ""
         visible: false
-        //text: ctx ? ctx.errorInitMsg : ""
-        //visible: ctx.errorInitMsg != ""
     }
 }
diff --git a/pkg/backend/callbacks.go b/pkg/backend/callbacks.go
index 5ea3b0484039c4a97d55e23bf0c155ea2264ff9c..f3bb39fb2ad2f1629ff53a3f5295f675d4b93fb2 100644
--- a/pkg/backend/callbacks.go
+++ b/pkg/backend/callbacks.go
@@ -7,7 +7,7 @@ import (
 	"unsafe"
 )
 
-/* NOTE! ATCHUNG! what follow are not silly comments. Well, *this one* is, but
+/* ATCHUNG! what follow are not silly comments. Well, *this one* is, but
    the lines after this are not.
    Those are inline C functions, that are invoked by CGO later on.
    it's also crucial that you don't any extra space between the function
diff --git a/pkg/backend/donate.go b/pkg/backend/donate.go
index d21668769c782a143d106e4701c755b6f151fe70..608128f4e87f7e8641c5941a62fd8c32d42a5174 100644
--- a/pkg/backend/donate.go
+++ b/pkg/backend/donate.go
@@ -3,8 +3,17 @@ package backend
 import (
 	"log"
 	"time"
+
+	"0xacab.org/leap/bitmask-vpn/pkg/config"
 )
 
+func wantDonations() bool {
+	if config.AskForDonations == "true" {
+		return true
+	}
+	return false
+}
+
 func needsDonationReminder() bool {
 	return ctx.cfg.NeedsDonationReminder()
 }
diff --git a/pkg/backend/bitmask.go b/pkg/backend/init.go
similarity index 64%
rename from pkg/backend/bitmask.go
rename to pkg/backend/init.go
index 2b5885965c91d4bbcdff851b0f27c89cb43b9a26..5abb05ecd122a622ca17ecd7c6cd147b3da12b0b 100644
--- a/pkg/backend/bitmask.go
+++ b/pkg/backend/init.go
@@ -9,43 +9,6 @@ import (
 	"0xacab.org/leap/bitmask-vpn/pkg/config/version"
 )
 
-func initializeBitmask() {
-	if ctx == nil {
-		log.Println("error: cannot initialize bitmask, ctx is nil")
-		os.Exit(1)
-	}
-	bitmask.InitializeLogger()
-
-	b, err := bitmask.InitializeBitmask()
-	if err != nil {
-		log.Println("error: cannot initialize bitmask")
-	}
-	ctx.bm = b
-	ctx.cfg = config.ParseConfig()
-}
-
-func startVPN() {
-	err := ctx.bm.StartVPN(ctx.Provider)
-	if err != nil {
-		log.Println(err)
-		os.Exit(1)
-	}
-}
-
-func stopVPN() {
-	err := ctx.bm.StopVPN()
-	if err != nil {
-		log.Println(err)
-	}
-}
-
-func wantDonations() bool {
-	if config.AskForDonations == "true" {
-		return true
-	}
-	return false
-}
-
 // initializeContext initializes an empty connStatus and assigns it to the
 // global ctx holder. This is expected to be called only once, so the public
 // api uses the sync.Once primitive to call this.
@@ -62,6 +25,50 @@ func initializeContext(provider, appName string) {
 		Version:         version.VERSION,
 		Status:          st,
 	}
+	errCh := make(chan string)
 	go trigger(OnStatusChanged)
-	initializeBitmask()
+	go checkErrors(errCh)
+	initializeBitmask(errCh)
+}
+
+func checkErrors(errCh chan string) {
+	for {
+		err := <-errCh
+		ctx.Errors = err
+		go trigger(OnStatusChanged)
+	}
+}
+
+func initializeBitmask(errCh chan string) {
+	if ctx == nil {
+		log.Println("bug: cannot initialize bitmask, ctx is nil!")
+		os.Exit(1)
+	}
+	bitmask.InitializeLogger()
+
+	b, err := bitmask.InitializeBitmask()
+	if err != nil {
+		log.Println("error: cannot initialize bitmask")
+		errCh <- err.Error()
+		return
+	}
+
+	helpers, privilege, err := b.VPNCheck()
+
+	if err != nil {
+		log.Println("error doing vpn check")
+		errCh <- err.Error()
+	}
+
+	if helpers == false {
+		log.Println("no helpers")
+		errCh <- "nohelpers"
+	}
+	if privilege == false {
+		log.Println("no polkit")
+		errCh <- "nopolkit"
+	}
+
+	ctx.bm = b
+	ctx.cfg = config.ParseConfig()
 }
diff --git a/pkg/backend/status.go b/pkg/backend/status.go
index 84b27b7cc022ae983d24e9cd7ee66d0801e4ec72..2e9c282db5f0ab0a143ff5d75a35ec66416ae692 100644
--- a/pkg/backend/status.go
+++ b/pkg/backend/status.go
@@ -35,6 +35,7 @@ type connectionCtx struct {
 	DonateDialog    bool   `json:"donateDialog"`
 	DonateURL       string `json:"donateURL"`
 	Version         string `json:"version"`
+	Errors          string `json:"errors"`
 	Status          status `json:"status"`
 	bm              bitmask.Bitmask
 	cfg             *config.Config
diff --git a/pkg/bitmask/init.go b/pkg/bitmask/init.go
index 7f10ab9db2aee61a399b2cc56132a5599e293b10..33a5911fa2a0cd5520ed13460392cf57e8e4e841 100644
--- a/pkg/bitmask/init.go
+++ b/pkg/bitmask/init.go
@@ -68,15 +68,17 @@ func InitializeBitmask() (Bitmask, error) {
 	defer pid.ReleasePID()
 
 	conf := config.ParseConfig()
-	conf.Version = "unknown"
 	conf.Printer = initPrinter()
 
 	b, err := initBitmask(conf.Printer)
 	if err != nil {
-		// TODO notify failure
-		log.Fatal(err)
+		return nil, err
+	}
+
+	err = checkAndStartBitmask(b, conf)
+	if err != nil {
+		return nil, err
 	}
-	go checkAndStartBitmask(b, conf)
 
 	var as Autostart
 	if conf.DisableAustostart {
@@ -84,6 +86,7 @@ func InitializeBitmask() (Bitmask, error) {
 	} else {
 		as = newAutostart(config.ApplicationName, "")
 	}
+
 	err = as.Enable()
 	if err != nil {
 		log.Printf("Error enabling autostart: %v", err)
@@ -100,40 +103,20 @@ func initPrinter() *message.Printer {
 	return message.NewPrinter(message.MatchLanguage(locale, "en"))
 }
 
-func checkAndStartBitmask(b Bitmask, conf *config.Config) {
+func checkAndStartBitmask(b Bitmask, conf *config.Config) error {
 	if conf.Obfs4 {
 		err := b.UseTransport("obfs4")
 		if err != nil {
 			log.Printf("Error setting transport: %v", err)
+			return err
 		}
 	}
-	err := checkAndInstallHelpers(b)
-	if err != nil {
-		log.Printf("Is bitmask running? %v", err)
-		os.Exit(1)
-	}
-	err = maybeStartVPN(b, conf)
+
+	err := maybeStartVPN(b, conf)
 	if err != nil {
 		log.Println("Error starting VPN: ", err)
-	}
-}
-
-func checkAndInstallHelpers(b Bitmask) error {
-	helpers, privilege, err := b.VPNCheck()
-	if (err != nil && err.Error() == "nopolkit") || (err == nil && !privilege) {
-		log.Printf("No polkit found")
-		os.Exit(1)
-	} else if err != nil {
-		log.Printf("Error checking vpn: %v", err)
 		return err
 	}
-
-	if !helpers {
-		err = b.InstallHelpers()
-		if err != nil {
-			log.Println("Error installing helpers: ", err)
-		}
-	}
 	return nil
 }
 
diff --git a/pkg/config/gui.go b/pkg/config/gui.go
index 5fa4886fcf3963d308cf105ec3c36e82ff17f8a8..7f2515ce8d36617f34a83b9284abcc1085dc9f3b 100644
--- a/pkg/config/gui.go
+++ b/pkg/config/gui.go
@@ -48,7 +48,6 @@ type Config struct {
 	Obfs4             bool
 	DisableAustostart bool
 	StartVPN          bool
-	Version           string
 	Printer           *message.Printer
 }
 
diff --git a/pkg/vpn/launcher_linux.go b/pkg/vpn/launcher_linux.go
index 71a74eafd443ef89da49b92266ed23397ed2ccf0..f92cf6ff767570778326b92598423025a80f7c91 100644
--- a/pkg/vpn/launcher_linux.go
+++ b/pkg/vpn/launcher_linux.go
@@ -1,5 +1,5 @@
 // +build linux
-// Copyright (C) 2018 LEAP
+// Copyright (C) 2018-2020 LEAP
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -53,32 +53,49 @@ func (l *launcher) close() error {
 	return nil
 }
 
-func (l *launcher) check() (helpers bool, priviledge bool, err error) {
+func (l *launcher) check() (helpers bool, privilege bool, err error) {
+	hasHelpers, err := hasHelpers()
+	if err != nil {
+		return
+	}
+	if !hasHelpers {
+		return false, true, nil
+	}
 
-	/*
-		isRunning, err := isPolkitRunning()
+	isRunning, err := isPolkitRunning()
+	if err != nil {
+		return
+	}
+
+	if !isRunning {
+		polkitPath := getPolkitPath()
+		if polkitPath == "" {
+			return true, false, nil
+		}
+		cmd := exec.Command("setsid", polkitPath)
+		err = cmd.Start()
 		if err != nil {
 			return
 		}
-		if !isRunning {
-			polkitPath := getPolkitPath()
-			if polkitPath == "" {
-				return true, false, nil
-			}
-			cmd := exec.Command("setsid", polkitPath)
-			err = cmd.Start()
-			if err != nil {
-				return
-			}
-			isRunning, err = isPolkitRunning()
-			return true, isRunning, err
-		}
-	*/
+		isRunning, err = isPolkitRunning()
+		return true, isRunning, err
+	}
 
 	return true, true, nil
 }
 
+func hasHelpers() (bool, error) {
+	/* TODO add polkit file too */
+	for _, f := range bitmaskRootPaths {
+		if _, err := os.Stat(f); err == nil {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
 func isPolkitRunning() (bool, error) {
+	// TODO shouldn't we also check for polkitd running?
 	var polkitProcNames = [...]string{
 		"polkit-gnome-authentication-agent-1",
 		"polkit-kde-authentication-agent-1",
diff --git a/pkg/vpn/main.go b/pkg/vpn/main.go
index ce599c94db1571cf2d40ebb187334c5d33c4dee3..9d59131bd9e7c8b159a3284cde68958ddd7c0bce 100644
--- a/pkg/vpn/main.go
+++ b/pkg/vpn/main.go
@@ -51,10 +51,13 @@ func Init() (*Bitmask, error) {
 	}
 	b := Bitmask{tempdir, statusCh, nil, bonafide, launch, "", nil}
 
-	err = b.StopVPN()
-	if err != nil {
-		return nil, err
-	}
+	/*
+		err = b.StopVPN()
+		if err != nil {
+			return nil, err
+		}
+	*/
+
 	err = ioutil.WriteFile(b.getCaCertPath(), config.CaCert, 0600)
 
 	go b.openvpnManagement()
diff --git a/pkg/vpn/openvpn.go b/pkg/vpn/openvpn.go
index a75b830af0ea7abef18f8f30240f2f6e1fade0a2..984aa09c8778e11ec2744ec0fd58db04ba5e3230 100644
--- a/pkg/vpn/openvpn.go
+++ b/pkg/vpn/openvpn.go
@@ -207,14 +207,13 @@ func (b *Bitmask) GetStatus() (string, error) {
 	return status, nil
 }
 
-// InstallHelpers into the system
 func (b *Bitmask) InstallHelpers() error {
-	// TODO
+	// TODO use pickle module from here
 	return nil
 }
 
 // VPNCheck returns if the helpers are installed and up to date and if polkit is running
-func (b *Bitmask) VPNCheck() (helpers bool, priviledge bool, err error) {
+func (b *Bitmask) VPNCheck() (helpers bool, privilege bool, err error) {
 	return b.launch.check()
 }