diff --git a/cocoa/dlg.go b/cocoa/dlg.go
index f8b3fc3595c49c8ece2083d7de7ef576fb82d430..d43dc8fb8543938fbd665bbc3780552115733ebb 100644
--- a/cocoa/dlg.go
+++ b/cocoa/dlg.go
@@ -11,20 +11,43 @@ import (
 	"unsafe"
 )
 
-func nsStr(s string) unsafe.Pointer {
-	return C.NSStr(unsafe.Pointer(&[]byte(s)[0]), C.int(len(s)))
+type AlertParams struct {
+	p C.AlertDlgParams
 }
 
-func YesNoDlg(msg string, title string) bool {
-	p := C.AlertDlgParams{
-		msg: C.CString(msg),
-	}
-	defer C.free(unsafe.Pointer(p.msg))
+func mkAlertParams(msg, title string, style C.AlertStyle) *AlertParams {
+	a := AlertParams{C.AlertDlgParams{msg: C.CString(msg), style: style}}
 	if title != "" {
-		p.title = C.CString(title)
-		defer C.free(unsafe.Pointer(p.title))
+		a.p.title = C.CString(title)
+	}
+	return &a
+}
+
+func (a *AlertParams) run() C.DlgResult {
+	return C.alertDlg(&a.p)
+}
+
+func (a *AlertParams) free() {
+	C.free(unsafe.Pointer(a.p.msg))
+	if a.p.title != nil {
+		C.free(unsafe.Pointer(a.p.title))
 	}
-	return C.alertDlg(&p) == C.DLG_OK
+}
+
+func nsStr(s string) unsafe.Pointer {
+	return C.NSStr(unsafe.Pointer(&[]byte(s)[0]), C.int(len(s)))
+}
+
+func YesNoDlg(msg, title string) bool {
+	a := mkAlertParams(msg, title, C.MSG_YESNO)
+	defer a.free()
+	return a.run() == C.DLG_OK
+}
+
+func ErrorDlg(msg, title string) {
+	a := mkAlertParams(msg, title, C.MSG_ERROR)
+	defer a.free()
+	a.run()
 }
 
 func FileDlg(save int, title string, exts []string, relaxExt bool) (string, error) {
diff --git a/cocoa/dlg.h b/cocoa/dlg.h
index 3bb9a67a3458c2b197f149a0dafdd06707bf9eec..108cc5dec6b37ad7de091302c2ae41ef1b42774d 100644
--- a/cocoa/dlg.h
+++ b/cocoa/dlg.h
@@ -1,8 +1,14 @@
 #include <objc/NSObjcRuntime.h>
 
+typedef enum {
+	MSG_YESNO,
+	MSG_ERROR,
+} AlertStyle;
+
 typedef struct {
 	char* msg;
 	char* title;
+	AlertStyle style;
 } AlertDlgParams;
 
 typedef struct {
diff --git a/cocoa/dlg.m b/cocoa/dlg.m
index ad24b09077a144e7e91363ca1734c09a4672d617..448f419af2f045981eb861b3038ea964f6ed46e1 100644
--- a/cocoa/dlg.m
+++ b/cocoa/dlg.m
@@ -38,8 +38,16 @@ DlgResult alertDlg(AlertDlgParams* params) {
 		[[alert window] setTitle:[[NSString alloc] initWithUTF8String:self->params->title]];
 	}
 	[alert setMessageText:[[NSString alloc] initWithUTF8String:self->params->msg]];
-	[alert addButtonWithTitle:@"Yes"];
-	[alert addButtonWithTitle:@"No"];
+	switch (self->params->style) {
+	case MSG_YESNO:
+		[alert addButtonWithTitle:@"Yes"];
+		[alert addButtonWithTitle:@"No"];
+		break;
+	case MSG_ERROR:
+		[alert setIcon:[NSImage imageNamed:NSImageNameCaution]];
+		[alert addButtonWithTitle:@"OK"];
+		break;
+	}
 	self->result = [alert runModal] == NSAlertFirstButtonReturn ? DLG_OK : DLG_CANCEL;
 	return self->result;
 }
diff --git a/dlgs.go b/dlgs.go
index c1d863a91d934b7b5aee58f3eb63a28c2967a2ea..9e035f567755635d003aee6708374c52744d3b87 100644
--- a/dlgs.go
+++ b/dlgs.go
@@ -46,6 +46,11 @@ func (b *MsgBuilder) YesNo() bool {
 	return b.yesNo()
 }
 
+/* Error spawns the message dialog with an error icon and single button, "Ok". */
+func (b *MsgBuilder) Error() {
+	b.error()
+}
+
 /* FileFilter represents a category of files (eg. audio files, spreadsheets). */
 type FileFilter struct {
 	Desc string
diff --git a/dlgs_darwin.go b/dlgs_darwin.go
index 64fa1bf0f890a816639f73c58aff0e1d7db40e78..a5e5db7e653ce1145335a457bab3b54cd07e0937 100644
--- a/dlgs_darwin.go
+++ b/dlgs_darwin.go
@@ -8,6 +8,10 @@ func (b *MsgBuilder) yesNo() bool {
 	return cocoa.YesNoDlg(b.Msg, b.Dlg.Title)
 }
 
+func (b *MsgBuilder) error() {
+	cocoa.ErrorDlg(b.Msg, b.Dlg.Title)
+}
+
 func (b *FileBuilder) load() (string, error) {
 	return b.run(0)
 }
diff --git a/dlgs_linux.go b/dlgs_linux.go
index d286de248a5b2083154f18e2b389d39d1d606614..5f9423bb0a1812d565b235b396179cdc6969a544 100644
--- a/dlgs_linux.go
+++ b/dlgs_linux.go
@@ -29,6 +29,13 @@ func (b *MsgBuilder) yesNo() bool {
 	return dlg.Run() == gtk.RESPONSE_YES
 }
 
+func (b *MsgBuilder) error() {
+	dlg := gtk.NewMessageDialog(nil, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "%s", b.Msg)
+	dlg.SetTitle(firstOf(b.Dlg.Title, "Error"))
+	defer closeDialog(&dlg.Dialog)
+	dlg.Run()
+}
+
 func (b *FileBuilder) load() (string, error) {
 	return chooseFile("Load", gtk.FILE_CHOOSER_ACTION_OPEN, b)
 }
diff --git a/dlgs_windows.go b/dlgs_windows.go
index a61dcf6c84245ff287f7cd4b92c4b7b0c842c613..de78a3cadae98278dfb2e43b1601f1510cc3917c 100644
--- a/dlgs_windows.go
+++ b/dlgs_windows.go
@@ -28,6 +28,10 @@ func (b *MsgBuilder) yesNo() bool {
 	return r == w32.IDYES
 }
 
+func (b *MsgBuilder) error() {
+	w32.MessageBox(w32.HWND(0), firstOf(b.Dlg.Title, "Error"), b.Msg, w32.MB_OK | w32.MB_ICONERROR)
+}
+
 type filedlg struct {
 	buf []uint16
 	filters []uint16
diff --git a/example/wde/main.go b/example/wde/main.go
index b3676c279a78b3d4fc71fc35431fbd38816498ed..833e3440fd1708d2015a8a0cb6f568b27cb8581c 100644
--- a/example/wde/main.go
+++ b/example/wde/main.go
@@ -48,6 +48,8 @@ func events(events <-chan interface{}) {
 				fmt.Println(dialog.Message("Is this sentence false?").YesNo())
 			case e.Glyph == "b":
 				fmt.Println(dialog.Message("R U OK?").Title("Just checking").YesNo())
+			case e.Glyph == "c":
+				dialog.Message("Operation failed").Error()
 			}
 		case wde.CloseEvent:
 			wde.Stop()