Skip to content

'Unhandled promise error: index out of bounds' with mirai_map and .promise #282

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
olivier7121 opened this issue May 15, 2025 · 1 comment
Labels
reprex needs a minimal reproducible example

Comments

@olivier7121
Copy link

olivier7121 commented May 15, 2025

This is an error that is occurring in my specific use case (not published here).
From this specific use case I built a reprex (that is unfortunately a bit long even if I tried to simplify/shorten it as much as possible) that I append to these explanations.
Out of 400 promises, a few (~between 3 and 8) are not fulfilled, but I am not able to catch them (via onRejected) and print the related error message.

[EDIT 1]: This issue starts to appear from 5 daemons onwards. The computer I'm using has 4 physical cores and 8 logical ones.

As a result of these errors, the code after the mirai_map completes is not executed, so that means that 1) the progress bar stops its progress and doesn't eventually close, 2) the timer doesn't stop either, 3) the final result of the mirai_map is not displayed in the console, 4) the animated 'Processing...' button doesn't revert to its 'ready' state, and 5) the daemons are not closed.

Did I miss something or is it really a bug?

[EDIT 2]: Interestingly this error no longer occurs when I set dispatcher = TRUE (the default setting). But then I go back to the other issue with the probable maximum size on globals. And in my use case, the whole process takes much more time with this setting .

library(shiny)
library(bslib)
library(mirai)
library(promises)
library(openxlsx)

TIMER_NOT_STARTED <- 0L
TIMER_RUNNING <- 1L
TIMER_FINISHED <- 2L

EMPTY_TEXT <- ""

if(!("MySet" %in% names(Progress$public_methods)))
{
	Progress$set("public", "MySet", function(value, message, detail, session = getDefaultReactiveDomain()) {
		self$set(value, message, "")
		session$sendCustomMessage("parseText", detail)
	})
}

GenerateExcelFiles <- function(Row)
{
	Number <- paste0(paste0(rep("0", NCharTotalNRows - nchar(Row)), collapse = ""), Row)
	OutputFile_Individual <- file.path(OutputFolder, paste0("Reprex mirai_map with 'Unhandled promise error'_", Number, ".xlsx"))
	Workbook_Individual <- createWorkbook()
	saveWorkbook(wb = Workbook_Individual, file = OutputFile_Individual, overwrite = TRUE)
	
	Row_wo_Year_Workbook_Central <- c(paste0('"', c(Number), '"'), 1)
	
	Selected_Years <- YE_Range[c(TRUE, runif(n = 5) > 0.5)]
	
	Row_w_Year_Workbook_Central <- unlist(lapply(X = Selected_Years, FUN = function(Year){
		n_rows_columns <- 100 + ceiling(200 * runif(n = 1))
		Random_Matrix <- as.data.frame(matrix(rnorm(n_rows_columns * n_rows_columns), nrow = n_rows_columns))
		addWorksheet(wb = Workbook_Individual, sheetName = paste0("Sheet_", Year), zoom = 100, gridLines = FALSE)
		writeData(wb = Workbook_Individual, sheet = paste0("Sheet_", Year), x = Random_Matrix, startRow = 1, startCol = 1)
		c(Year, n_rows_columns)
	}))
	saveWorkbook(wb = Workbook_Individual, file = OutputFile_Individual, overwrite = TRUE)
	list("Selected_Years" = Selected_Years, "Row" = Row, "Row_Workbook_Central" = c(Row_wo_Year_Workbook_Central, Row_w_Year_Workbook_Central, "\n"))
}

ui <- fluidPage(
	tags$head(
		tags$style(
			HTML("
				.shiny-notification {
					position: fixed;
					bottom: 0;
					right: 0;
					background-color: #e8e8e8;
					color: #333;
					border: 1px solid #ccc;
					border-radius: 3px;
					opacity: 1;
					padding: 10px 2rem 10px 10px;
					margin: 5px
				}
				.shiny-notification-message {
					color: #31708f;
					background-color: #d9edf7;
					border: 1px solid #bce8f1
				}
				.shiny-notification-warning {
					color: #8a6d3b;
					background-color: #fcf8e3;
					border: 1px solid #faebcc
				}
				.shiny-notification-error {
					color: #a94442;
					background-color: #f2dede;
					border: 1px solid #ebccd1
				}
				.progress-message, .progress-detail {
					float: left;
					clear: left
				}
				.grey-out {
					color: lightgrey;
				}
			")
		),
		tags$script("
				$(document).ready(function(){
					Shiny.addCustomMessageHandler('parseText', function(detail) {
						$('.progress-detail')[0].innerHTML = detail;
					});
				})
		")
	),
	titlePanel("Reprex mirai_map with 'Unhandled promise error'"),
	
	sidebarLayout(
		sidebarPanel(
			input_task_button(id = "start", "Start")
		),
		
		mainPanel(
			textOutput("Timer")
		)
	)
)

server <- function(input, output, session) {
	Timer.Status <- reactiveVal(0)
	Timer.Start <- reactiveVal(0)
	Timer.End <- reactiveVal(0)
	
	Rows <- 1:400
	YE_Range <- 2020:2025
	
	output$Timer <- renderText({
		Status <- Timer.Status()
		if(Status == TIMER_NOT_STARTED)
		{
			EMPTY_TEXT
		} else if(Status == TIMER_RUNNING)
		{
			invalidateLater(1000L)
			Timer.End(as.integer(Sys.time()))
			paste("Time elapsed:", format(as.POSIXct(Timer.End() - Timer.Start() - 3600L), "%H:%M:%S"))
		} else if(Status == TIMER_FINISHED)
		{
			paste("Time elapsed:", format(as.POSIXct(Timer.End() - Timer.Start() - 3600L), "%H:%M:%S"))
		}
	})
	
	# Handle button click
	observeEvent(input$start,{
		Timer.Status(TIMER_RUNNING)
		Timer.Start(as.integer(Sys.time()))
		
		TotalNRows <<- length(Rows)
		NCharTotalNRows <<- nchar(length(Rows))
		
		OutputFolder <<- file.path(".", "Output")
		if(!dir.exists(OutputFolder))	dir.create(OutputFolder)
		
		NDameons <- 7
		
		progress <- Progress$new(session, min = 0, max = TotalNRows)
		progress$set(message = paste("Parallel calculation in progress on", NDameons, "daemons"), detail = "Starting...")
		
		daemons(NDameons, dispatcher = FALSE)
		
		NRows_reactive <- reactiveVal(0)
		
		Variables2Share <- list("YE_Range" = YE_Range, "NCharTotalNRows" = NCharTotalNRows, "OutputFolder" = OutputFolder)
		everywhere({
			lapply(c("openxlsx"), library, character.only = TRUE)
			},
			as.environment(Variables2Share)
		)
		
		mirai_map(
			.x = Rows,
			.f = GenerateExcelFiles,
			GenerateExcelFiles = GenerateExcelFiles,
			.promise = list(
				onFulfilled = function(result){
					Selected_Years <- result[["Selected_Years"]]
					NRows_reactive(NRows_reactive() + 1)
					progress$MySet(value = NRows_reactive(), message = paste0("Parallel calculation in progress on ", NDameons, " daemons (", round(100 * NRows_reactive() / TotalNRows), "%)"), detail = paste0(NRows_reactive(), " / ", TotalNRows, " rows processed<br><b>Last processed row</b><br>", result[["Row"]], "<br>", "Years selected: ", paste(Selected_Years, collapse = ' - ')))
				},
				onRejected = function(x){cat(conditionMessage(x), "\n"); daemons(0)}
			)
		) %...>% {
			Row_Workbook_Central <- unlist(lapply(X = ., FUN = function(item) item[["Row_Workbook_Central"]]))
			cat(c("\n", Row_Workbook_Central))
			Timer.End(as.integer(Sys.time()))
			Timer.Status(TIMER_FINISHED)
			update_task_button(id = "start", state = "ready")
			progress$close()
			daemons(0)
			print(paste("Time elapsed:", format(as.POSIXct(Timer.End() - Timer.Start() - 3600L), "%H:%M:%S")))
		}
		update_task_button(id = "start", state = "busy")
	})
}

# Run the application
shinyApp(ui = ui, server = server)

Additional information:

> sessionInfo()
R version 4.5.0 (2025-04-11 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 10 x64 (build 19045)

Matrix products: default
  LAPACK version 3.12.1

locale:
[1] LC_COLLATE=French_France.utf8  LC_CTYPE=French_France.utf8    LC_MONETARY=French_France.utf8 LC_NUMERIC=C                   LC_TIME=French_France.utf8    

time zone: Europe/Berlin
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_4.5.0 tools_4.5.0   
> packageVersion("mirai")
[1] ‘2.2.0’
> packageVersion("promises")
[1] ‘1.3.2’
@shikokuchuo shikokuchuo added the reprex needs a minimal reproducible example label May 21, 2025
@shikokuchuo
Copy link
Member

If you can post a reprex that is more minimal and does not use 'openxlsx', I could take a closer look. If only manifests with the use of everywhere(), I posted on your other discussion topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
reprex needs a minimal reproducible example
Projects
None yet
Development

No branches or pull requests

2 participants