diff --git a/bin/efa b/bin/efa
index 6117ec6ed7b84af2840746ee6ff764ba24b4fc20..ad57e016be8edc123f3eb4717c660b4f7d68e2b8 100755
--- a/bin/efa
+++ b/bin/efa
@@ -104,10 +104,6 @@ if ($efa->{'error'}) {
 	die $efa->{'error'}->as_string();
 }
 
-if ($efa->isa('WWW::Efa::Error')) {
-	die($efa->as_string);
-}
-
 if ($opt->{'test-parse'}) {
 	local $/ = undef;
 	$efa->{'html_reply'} = <STDIN>;
diff --git a/lib/WWW/Efa.pm b/lib/WWW/Efa.pm
index b5fb724c200da22b4b0346327e75783ae60d4b76..38eeecf1b0d59234879f0671932d256bf30c52da 100644
--- a/lib/WWW/Efa.pm
+++ b/lib/WWW/Efa.pm
@@ -40,7 +40,8 @@ use 5.010;
 use base 'Exporter';
 
 use XML::LibXML;
-use WWW::Efa::Error;
+use WWW::Efa::Error::Setup;
+use WWW::Efa::Error::Backend;
 use WWW::Mechanize;
 
 our @EXPORT_OK = ();
@@ -60,8 +61,8 @@ sub post_time {
 	}
 
 	if ($time !~ / ^ [0-2]? \d : [0-5]? \d $ /x) {
-		die WWW::Efa::Error->new(
-			'internal', 'conf', ['time', $time, 'Must match HH:MM']
+		die WWW::Efa::Error::Setup->new(
+			'time', $time, 'Must match HH:MM'
 		);
 	}
 	@{$post}{'itdTimeHour', 'itdTimeMinute'} = split(/:/, $time);
@@ -71,8 +72,8 @@ sub post_date {
 	my ($post, $date) = @_;
 
 	if ($date !~ /^ [0-3]? \d \. [01]? \d \. (?: \d{4} )? $/x) {
-		die WWW::Efa::Error->new(
-			'internal', 'conf', ['date', $date, 'Must match DD.MM.[YYYY]']
+		die WWW::Efa::Error::Setup->new(
+			'date', $date, 'Must match DD.MM.[YYYY]'
 		);
 	}
 	@{$post}{'itdDateDay', 'itdDateMonth', 'itdDateYear'} = split(/\./, $date);
@@ -95,13 +96,10 @@ sub post_exclude {
 			}
 		}
 		if (not $ok) {
-			die WWW::Efa::Error->new(
-				'internal', 'conf',
-				[
-					'exclude',
-					join(q{ }, @exclude),
-					'Must consist of ' . join(q{ }, @mapping)
-				]
+			die WWW::Efa::Error::Setup->new(
+				'exclude',
+				join(q{ }, @exclude),
+				'Must consist of ' . join(q{ }, @mapping)
 			);
 		}
 	}
@@ -115,9 +113,8 @@ sub post_prefer {
 		when ('nowait') { $post->{'routeType'} = 'LEASTINTERCHANGE' }
 		when ('nowalk') { $post->{'routeType'} = 'LEASTWALKING' }
 		default {
-			die WWW::Efa::Error->new(
-				'internal', 'conf',
-				['prefer', $prefer, 'Must be either speed, nowait or nowalk']
+			die WWW::Efa::Error::Setup->new(
+				'prefer', $prefer, 'Must be either speed, nowait or nowalk'
 			);
 		}
 	}
@@ -131,9 +128,8 @@ sub post_include {
 		when ('ic')    { $post->{'lineRestriction'} = 401 }
 		when ('ice')   { $post->{'lineRestriction'} = 400 }
 		default {
-			die WWW::Efa::Error->new(
-				'internal', 'conf',
-				['include', $include, 'Must be one of local/ic/ice']
+			die WWW::Efa::Error::Setup->new(
+				'include', $include, 'Must be one of local/ic/ice'
 			);
 		}
 	}
@@ -146,9 +142,8 @@ sub post_walk_speed {
 		$post->{'changeSpeed'} = $walk_speed;
 	}
 	else {
-		die WWW::Efa::Error->new(
-			'internal', 'conf',
-			['walk_speed', $walk_speed, 'Must be normal, fast or slow']
+		die WWW::Efa::Error::Setup->new(
+			'walk_speed', $walk_speed, 'Must be normal, fast or slow'
 		);
 	}
 }
@@ -157,9 +152,8 @@ sub post_place {
 	my ($post, $which, $place, $stop, $type) = @_;
 
 	if (not ($place and $stop)) {
-		die WWW::Efa::Error->new(
-			'internal', 'conf',
-			['place', $which, "Need at least two elements"]
+		die WWW::Efa::Error::Setup->new(
+			'place', $which, "Need at least two elements"
 		);
 	}
 
@@ -263,8 +257,8 @@ sub parse_initial {
 		return $cons;
 	}
 	else {
-		return WWW::Efa::Error->new(
-			'efa.vrr.de', 'no data'
+		return WWW::Efa::Error::Backend->new(
+			'no data'
 		);
 	}
 }
@@ -334,7 +328,7 @@ sub new {
 	eval {
 		$ref->{'post'} = create_post(\%conf);
 	};
-	if ($@ and ref($@) eq 'WWW::Efa::Error') {
+	if ($@ and ref($@) eq 'WWW::Efa::Error::Setup') {
 		$ref->{'error'} = $@;
 	}
 
@@ -398,8 +392,8 @@ sub check_ambiguous {
 			push(@possible, $val->textContent());
 		}
 
-		return WWW::Efa::Error->new(
-			'efa.vrr.de', 'ambiguous',
+		return WWW::Efa::Error::Backend->new(
+			'ambiguous',
 			\@possible
 		);
 	}
@@ -415,8 +409,8 @@ sub check_no_connections {
 	my $err_node = $tree->findnodes($xp_err_img)->[0];
 
 	if ($err_node) {
-		return WWW::Efa::Error->new(
-			'efa.vrr.de', 'error',
+		return WWW::Efa::Error::Backend->new(
+			'error',
 			$err_node->parentNode()->parentNode()->textContent()
 		);
 	}
diff --git a/lib/WWW/Efa/Error.pm b/lib/WWW/Efa/Error.pm
deleted file mode 100644
index a5fbf963f64eb5b28854864c65f0cf9bf2a2510b..0000000000000000000000000000000000000000
--- a/lib/WWW/Efa/Error.pm
+++ /dev/null
@@ -1,60 +0,0 @@
-package WWW::Efa::Error;
-
-use strict;
-use warnings;
-use 5.010;
-
-use base 'Exporter';
-
-our @EXPORT_OK = qw{};
-
-# source: internal / efa.vrr.de
-# type: internal: conf
-#     efa.vrr.de: ambiguous / error / no data
-sub new {
-	my ($obj, $source, $type, $data) = @_;
-	my $ref = {};
-
-	$ref->{'source'} = $source;
-	$ref->{'type'}   = $type;
-	$ref->{'data'}   = $data;
-
-	return bless($ref, $obj);
-}
-
-sub as_string {
-	my ($self) = @_;
-	my $ret;
-
-	if ($self->{'source'} eq 'internal') {
-		$ret = sprintf(
-			"WWW::Efa config error: Wrong arg for option %s: %s\n%s\n",
-			@{$self->{'data'}}
-		);
-	}
-	elsif ($self->{'source'} eq 'efa.vrr.de') {
-		given ($self->{'type'}) {
-			when ('no data') {
-				$ret = "WWW::Efa: efa.vrr.de returned no data\n";
-			}
-			when ('ambiguous') {
-				$ret = sprintf(
-					"WWW::Efa: efa.vrr.de: Ambiguous input for %s:\n",
-					shift(@{$self->{'data'}}),
-				);
-				foreach my $possible (@{$self->{'data'}}) {
-					$ret .= "\t${possible}\n";
-				}
-			}
-			when ('error') {
-				$ret = sprintf(
-					"WWW::Efa: efa.vrr.de error:\n%s\n",
-					$self->{'data'},
-				);
-			}
-		}
-	}
-	return $ret;
-}
-
-1;
diff --git a/lib/WWW/Efa/Error/Backend.pm b/lib/WWW/Efa/Error/Backend.pm
new file mode 100644
index 0000000000000000000000000000000000000000..b6ffa75c97944c5d8ea13b101c2f73377f01716c
--- /dev/null
+++ b/lib/WWW/Efa/Error/Backend.pm
@@ -0,0 +1,48 @@
+package WWW::Efa::Error::Backend;
+
+use strict;
+use warnings;
+use 5.010;
+
+use base 'Exporter';
+
+our @EXPORT_OK = qw{};
+
+sub new {
+	my ($obj, $type, $data) = @_;
+	my $ref = {};
+
+	$ref->{'type'}   = $type;
+	$ref->{'data'}   = $data;
+
+	return bless($ref, $obj);
+}
+
+sub as_string {
+	my ($self) = @_;
+	my $ret;
+
+	given ($self->{'type'}) {
+		when ('no data') {
+			$ret = "WWW::Efa: efa.vrr.de returned no data\n";
+		}
+		when ('ambiguous') {
+			$ret = sprintf(
+				"WWW::Efa: efa.vrr.de: Ambiguous input for %s:\n",
+				shift(@{$self->{'data'}}),
+			);
+			foreach my $possible (@{$self->{'data'}}) {
+				$ret .= "\t${possible}\n";
+			}
+		}
+		when ('error') {
+			$ret = sprintf(
+				"WWW::Efa: efa.vrr.de error:\n%s\n",
+				$self->{'data'},
+			);
+		}
+	}
+	return $ret;
+}
+
+1;
diff --git a/lib/WWW/Efa/Error/Setup.pm b/lib/WWW/Efa/Error/Setup.pm
new file mode 100644
index 0000000000000000000000000000000000000000..521bb55875fbd977453e5bfec87927b7ae463ff6
--- /dev/null
+++ b/lib/WWW/Efa/Error/Setup.pm
@@ -0,0 +1,32 @@
+package WWW::Efa::Error::Setup;
+
+use strict;
+use warnings;
+use 5.010;
+
+use base 'Exporter';
+
+our @EXPORT_OK = qw{};
+
+sub new {
+	my ($obj, $key, $value, $msg) = @_;
+	my $ref = {};
+
+	$ref->{'key'}     = $key;
+	$ref->{'value'}   = $value;
+	$ref->{'message'} = $msg;
+
+	return bless($ref, $obj);
+}
+
+sub as_string {
+	my ($self) = @_;
+	my $ret;
+
+	return sprintf(
+		"WWW::Efa setup error: Wrong arg for option %s: %s\n%s\n",
+		@{$self}{'key', 'value', 'message'},
+	);
+}
+
+1;
diff --git a/t/50-www-efa.t b/t/50-www-efa.t
index 8a540253057788bdbda5f18b84bebba97fd7de12..e5272727b3f07403b7ea17a3551b30acecd3ed3e 100644
--- a/t/50-www-efa.t
+++ b/t/50-www-efa.t
@@ -3,7 +3,7 @@ use strict;
 use warnings;
 use 5.010;
 
-use Test::More tests => 127;
+use Test::More tests => 135;
 
 BEGIN {
 	use_ok('WWW::Efa');
@@ -77,28 +77,29 @@ sub is_efa_err {
 		"conf ok: $key => $val",
 	);
 
+	isa_ok($efa->{'error'}, 'WWW::Efa::Error::Setup');
+
 	is(
-		$efa->{'error'}->{'source'}, 'internal',
-		"$key => $val: Error source is internal",
+		$efa->{'error'}->{'key'}, $key,
+		"$key => $val: Error: Correct key",
 	);
 	is(
-		$efa->{'error'}->{'type'}, 'conf',
-		"$key => $val: Error type is conf",
+		$efa->{'error'}->{'value'}, $val_want,
+		"$key => $val: Error: Correct valuef",
 	);
-
-	is_deeply(
-		$efa->{'error'}->{'data'}, [$key, $val_want, $str],
-		"$key => $val: Error data is [$key, $val_want, $str]",
+	is(
+		$efa->{'error'}->{'message'}, $str,
+		"$key => $val: Error: String is '$str'",
 	);
 }
 
 is_efa_post('ignored', 'ignored');
 
 my $efa = new_ok('WWW::Efa' => []);
-isa_ok($efa->{'error'}, 'WWW::Efa::Error');
-is($efa->{'error'}->{'source'}, 'internal');
-is($efa->{'error'}->{'type'},   'conf'    );
-is_deeply($efa->{'error'}->{'data'},   ['place', 'origin', 'Need at least two elements']);
+isa_ok($efa->{'error'}, 'WWW::Efa::Error::Setup');
+is($efa->{'error'}->{'key'}, 'place');
+is($efa->{'error'}->{'value'}, 'origin');
+is($efa->{'error'}->{'message'}, 'Need at least two elements');
 
 is_efa_post(
 	'via', ['MH', 'HBf'],
diff --git a/t/60-bin-efa.t b/t/60-bin-efa.t
index 6bb9f5d93ce62d6539c6a28c9c905650aa228a44..8337b62cb1834043202466f994306798a575fb34 100644
--- a/t/60-bin-efa.t
+++ b/t/60-bin-efa.t
@@ -16,7 +16,7 @@ my $re_version = qr{\S*efa version \S+};
 sub mk_err {
 	my ($arg, $value, $message) = @_;
 	return sprintf(
-		"WWW::Efa config error: Wrong arg for option %s: %s\n%s\n",
+		"WWW::Efa setup error: Wrong arg for option %s: %s\n%s\n",
 		$arg, $value, $message
 	);
 }