diff --git a/doc/19-language-reference.md b/doc/19-language-reference.md
index c0d843b82..78379fe9a 100644
--- a/doc/19-language-reference.md
+++ b/doc/19-language-reference.md
@@ -760,6 +760,17 @@ The `continue` and `break` keywords can be used to control how the loop is execu
 skips over the remaining expressions for the loop body and begins the next loop evaluation. The `break` keyword
 breaks out of the loop.
 
+## <a id="throw"></a> Exceptions
+
+Built-in commands may throw exceptions to signal errors such as invalid arguments. User scripts can throw exceptions
+using the `throw` keyword.
+
+Example:
+
+    throw "An error occurred."
+
+There is currently no way for scripts to catch exceptions.
+
 ## <a id="types"></a> Types
 
 All values have a static type. The `typeof` function can be used to determine the type of a value:
diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll
index 25310d650..abe0a34c6 100644
--- a/lib/config/config_lexer.ll
+++ b/lib/config/config_lexer.ll
@@ -208,6 +208,7 @@ for				return T_FOR;
 if				return T_IF;
 else				return T_ELSE;
 while				return T_WHILE;
+throw				return T_THROW;
 =\>				return T_FOLLOWS;
 \<\<				return T_SHIFT_LEFT;
 \>\>				return T_SHIFT_RIGHT;
diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy
index 80e06ec8e..fd4e1995a 100644
--- a/lib/config/config_parser.yy
+++ b/lib/config/config_parser.yy
@@ -181,6 +181,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
 %token T_IF "if (T_IF)"
 %token T_ELSE "else (T_ELSE)"
 %token T_WHILE "while (T_WHILE)"
+%token T_THROW "throw (T_THROW)"
 %token T_FOLLOWS "=> (T_FOLLOWS)"
 %token T_NULLARY_LAMBDA_BEGIN "{{ (T_NULLARY_LAMBDA_BEGIN)"
 %token T_NULLARY_LAMBDA_END "}} (T_NULLARY_LAMBDA_END)"
@@ -680,6 +681,10 @@ lterm: type
 
 		$$ = new WhileExpression($3, $5, @$);
 	}
+	| T_THROW rterm
+	{
+		$$ = new ThrowExpression($2, @$);
+	}
 	| rterm_side_effect
 	;
 	
diff --git a/lib/config/configcompiler.cpp b/lib/config/configcompiler.cpp
index 4eb5766ed..6d7edccf2 100644
--- a/lib/config/configcompiler.cpp
+++ b/lib/config/configcompiler.cpp
@@ -50,7 +50,6 @@ ConfigCompiler::ConfigCompiler(const String& path, std::istream *input, const St
 ConfigCompiler::~ConfigCompiler(void)
 {
 	DestroyScanner();
-	delete m_Input;
 }
 
 /**
@@ -174,17 +173,6 @@ void ConfigCompiler::HandleLibrary(const String& library)
 	Utility::LoadExtensionLibrary(library);
 }
 
-void ConfigCompiler::CompileHelper(void)
-{
-	try {
-		m_Promise.set_value(boost::shared_ptr<Expression>(Compile()));
-	} catch (...) {
-		m_Promise.set_exception(boost::current_exception());
-	}
-
-	delete this;
-}
-
 /**
  * Compiles a stream.
  *
@@ -198,12 +186,15 @@ Expression *ConfigCompiler::CompileStream(const String& path, std::istream *stre
 
 	stream->exceptions(std::istream::badbit);
 
-	ConfigCompiler* ctx = new ConfigCompiler(path, stream, zone);
+	ConfigCompiler ctx(path, stream, zone);
 
-	boost::shared_future<boost::shared_ptr<Expression> > ftr = boost::shared_future<boost::shared_ptr<Expression> >(ctx->m_Promise.get_future());
-
-	Utility::QueueAsyncCallback(boost::bind(&ConfigCompiler::CompileHelper, ctx));
-	return new FutureExpression(ftr);
+	try {
+		return ctx.Compile();
+	} catch (const ScriptError& ex) {
+		return new ThrowExpression(MakeLiteral(ex.what()), ex.GetDebugInfo());
+	} catch (const std::exception& ex) {
+		return new ThrowExpression(MakeLiteral(DiagnosticInformation(ex)));
+	}
 }
 
 /**
@@ -216,10 +207,9 @@ Expression *ConfigCompiler::CompileFile(const String& path, const String& zone)
 {
 	CONTEXT("Compiling configuration file '" + path + "'");
 
-	std::ifstream *stream = new std::ifstream();
-	stream->open(path.CStr(), std::ifstream::in);
+	std::ifstream stream(path.CStr(), std::ifstream::in);
 
-	if (!*stream)
+	if (!stream)
 		BOOST_THROW_EXCEPTION(posix_error()
 			<< boost::errinfo_api_function("std::ifstream::open")
 			<< boost::errinfo_errno(errno)
@@ -228,7 +218,7 @@ Expression *ConfigCompiler::CompileFile(const String& path, const String& zone)
 	Log(LogInformation, "ConfigCompiler")
 	    << "Compiling config file: " << path;
 
-	return CompileStream(path, stream, zone);
+	return CompileStream(path, &stream, zone);
 }
 
 /**
@@ -240,8 +230,8 @@ Expression *ConfigCompiler::CompileFile(const String& path, const String& zone)
  */
 Expression *ConfigCompiler::CompileText(const String& path, const String& text, const String& zone)
 {
-	std::stringstream *stream = new std::stringstream(text);
-	return CompileStream(path, stream, zone);
+	std::stringstream stream(text);
+	return CompileStream(path, &stream, zone);
 }
 
 /**
diff --git a/lib/config/configcompiler.hpp b/lib/config/configcompiler.hpp
index e3b692c23..aa438473e 100644
--- a/lib/config/configcompiler.hpp
+++ b/lib/config/configcompiler.hpp
@@ -114,7 +114,7 @@ private:
 	void InitializeScanner(void);
 	void DestroyScanner(void);
 
-	void CompileHelper(void);
+	void HandleIncludeZone(const String& tag, const String& path, const String& pattern, std::vector<Expression *>& expressions);
 
 public:
 	bool m_Eof;
diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp
index 3b758dc49..171078289 100644
--- a/lib/config/expression.cpp
+++ b/lib/config/expression.cpp
@@ -674,6 +674,14 @@ void icinga::BindToScope(Expression *& expr, ScopeSpecifier scopeSpec)
 	}
 }
 
+ExpressionResult ThrowExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
+{
+	ExpressionResult messageres = m_Message->Evaluate(frame);
+	CHECK_RESULT(messageres);
+	Value message = messageres.GetValue();
+	BOOST_THROW_EXCEPTION(ScriptError(message, m_DebugInfo));
+}
+
 ExpressionResult ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
 {
 	String type = VMOps::GetField(frame.Self, "type", m_DebugInfo);
diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp
index 6f7dbfe53..ff0cbb586 100644
--- a/lib/config/expression.hpp
+++ b/lib/config/expression.hpp
@@ -225,28 +225,6 @@ private:
 	boost::shared_ptr<Expression> m_Expression;
 };
 
-class I2_CONFIG_API FutureExpression : public Expression
-{
-public:
-	FutureExpression(const boost::shared_future<boost::shared_ptr<Expression> >& future)
-		: m_Future(future)
-	{ }
-
-protected:
-	virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
-	{
-		return m_Future.get()->DoEvaluate(frame, dhint);
-	}
-
-	virtual const DebugInfo& GetDebugInfo(void) const
-	{
-		return m_Future.get()->GetDebugInfo();
-	}
-
-private:
-	mutable boost::shared_future<boost::shared_ptr<Expression> > m_Future;
-};
-
 class I2_CONFIG_API LiteralExpression : public Expression
 {
 public:
@@ -768,6 +746,25 @@ protected:
 
 I2_CONFIG_API void BindToScope(Expression *& expr, ScopeSpecifier scopeSpec);
 
+class I2_CONFIG_API ThrowExpression : public DebuggableExpression
+{
+public:
+	ThrowExpression(Expression *message, const DebugInfo& debugInfo = DebugInfo())
+		: DebuggableExpression(debugInfo), m_Message(message)
+	{ }
+
+	~ThrowExpression(void)
+	{
+		delete m_Message;
+	}
+
+protected:
+	virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const;
+
+private:
+	Expression *m_Message;
+};
+
 class I2_CONFIG_API ImportExpression : public DebuggableExpression
 {
 public: