0

I get this most common error message in shiny app. I am well aware of this error and have resolved it dozens of time. But this time I am stumped.

Listening on http://127.0.0.1:3933
Warning: Error in : Operation not allowed without an active reactive context.
* You tried to do something that can only be done from inside a reactive consumer.
  56: <Anonymous>
Error : Operation not allowed without an active reactive context.
* You tried to do something that can only be done from inside a reactive consumer.

I very well understand the meaning of the error but cannot find the offending line of code. Have read my entire server.R code (of around 200 lines) line by line several times but nowhere I see any reactive variable used outside of either a call to a reactive() function or an observe() or an eventReactive(). I have also searched for any spelling error in the above 3 main functions.

The problem is finding the offending line of code, as the error message does not include any line number (which is strange as it has not happened earlier).

Note: I can post the whole server.R code but right now I am asking 2 basic questions:

  1. Is it possible to get this error inside an observer or a reactive function?
  2. If yes then why am I not getting a line number?

UPDATE: Code for source.R & global.R are pasted below. Note: Most of data.tables that are used in server.R are created in global.R (hence showing global.R after removing function bodies, to reduce the size).

# source.R
suppressPackageStartupMessages(library(shiny))
suppressPackageStartupMessages(library(data.table))
suppressPackageStartupMessages(library(magrittr))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(dygraphs))
suppressPackageStartupMessages(library(gt))


options(shiny.reactlog=TRUE)

shinyServer(function(input, output,session) {
  
  # find out the terminal ID of the site
  termid <- eventReactive(input$site,{
    vehdt[name==input$site,term_id]
  })
  
  fueldt <- eventReactive(input$site,{
    RDS_file <- fuelfiles[Site==input$site,Filename]
    cat("\ntail of fueldt at site change:",append = T)
    fdt <- readRDS(RDS_file)
    print(fdt %>% tail)
    fdt
  })
  
  last_fuel_update_on <- eventReactive(input$site,{
    cat("\nReading last fuel time updated from RDS data:")
    fueldt()[,ts] %>% last %>% as.numeric()
  })
 
 
    
  # start extracting data for the site
  observeEvent(label = "site update",input$site, {
    dev_at_site <- devdt[Site==input$site,Device]
    updateRadioGroupButtons(session = session,inputId = "device1",label = "Device at site",choices = dev_at_site,selected = dev_at_site[1])
    updateRadioGroupButtons(session = session,inputId = "device2",label = "Device at site",choices = dev_at_site,selected = dev_at_site[2])
    updateRadioGroupButtons(session = session,inputId = "device3",label = "Device at site",choices = dev_at_site,selected = last(dev_at_site))
  },priority = 10)
  
  paramdt1 <- eventReactive(label = "Param update 1",eventExpr = input$device1,{
    devfile <- which_file(input$device1)
    cat("\nNew device file being searched..")
    if(file.exists(devfile)) {
      paramdt <- fread(devfile)
      cat(devfile)
    } else {
      message("Topic could not be mapped to any device. Using default ELM8420 parameters")
      paramdt <- fread("ELM8420.txt")
    }
    paramdt
  },ignoreNULL = T)
  
  paramdt2 <- eventReactive(label = "Param update 2",eventExpr = input$device2,{
    devfile <-  which_file(input$device2)
    cat("\nNew device file being searched..")
    if(file.exists(devfile)) {
      paramdt <- fread(devfile)
      cat(devfile)
    } else {
      message("Topic could not be mapped to any device. Using default ELM8420 parameters")
      paramdt <- fread("ELM8420.txt")
    }
    paramdt
  },ignoreNULL = T)
  
  paramdt3 <- eventReactive(label = "Param update 3",eventExpr = input$device3,{
    devfile <-  which_file(input$device3)
    cat("\nNew device file being searched..")
    if(file.exists(devfile)) {
      paramdt <- fread(devfile)
      cat(devfile)
    } else {
      message("Topic could not be mapped to any device. Using default ELM8420 parameters")
      paramdt <- fread("ELM8420.txt")
    }
    paramdt
  },ignoreNULL = T)
  
  observeEvent(label = "Parameter selector 1",eventExpr = paramdt1(), {
    paramcodes <- paramdt1()$code
    names(paramcodes) <- paramdt1()$name
    cat("\nChanged parameters to:",paramcodes)
    updateCheckboxGroupInput(session = session,inputId = "st1",choices = paramcodes,selected = paramcodes[1])
    updateBox(id = "chart1",action = "update",session = session,options = list(title=h2(paste(input$device1,input$st1))))
  },priority = 7)
  
  observeEvent(label = "Parameter selector 2",eventExpr = paramdt2(), {
    paramcodes <- paramdt2()$code
    names(paramcodes) <- paramdt2()$name
    cat("\nChanged parameters to:",paramcodes)
    updateCheckboxGroupInput(session = session,inputId = "st2",choices = paramcodes,selected = paramcodes[1])
    updateBox(id = "chart2",action = "update",session = session,options = list(title=h2(paste(input$device2,input$st2))))
  },priority = 6)
  
  observeEvent(label = "Parameter selector 3",eventExpr = paramdt3(), {
    paramcodes <- paramdt3()$code
    names(paramcodes) <- paramdt3()$name
    cat("\nChanged parameters to:",paramcodes)
    updateCheckboxGroupInput(session = session,inputId = "st3",choices = paramcodes, selected = paramcodes[2])
    updateBox(id = "chart3",action = "update",session = session,options = list(title=h2(paste(input$device3,input$st3))))
  },priority = 5)
  
  # ==== MAIN PROGAM STARTS=====
  xmqtt <- reactive(readRDS(dtfiles[Site==input$site,Filename]))
  ts_last <- reactive(xmqtt() %>% last(1) %>% .$TS)
    fileData <- reactive(reactiveFileReader(session = session,intervalMillis = 100000, filePath = mqfiles[Site==input$site,Filename],readFunc = read_lines) )


    r <-  reactiveValues(ftsd=fueldt(),atsd=apidt,j=jwt)
    
    observeEvent(autoInvalidate_api(),{
      cat("\nEntered in autoInvalidate_api()")
      r$j <- refresh_token(r$j)
      message("\nAPI Token was updated on:",attr(r$j,which = "updated"))
      cat("\nFuel next update of API starting from time stamp:",as.character(frUnix(last_fuel_update_on)))
      new_fuel_api_output <- 
        get_fuel_lev(base_airtel,tok = r$j,site = termid(),unixstart = last_fuel_update_on(),
                     unixend =  as.POSIXct(Sys.time()) %>% as.integer())
      cat("..DONE")
      events_omni <- 
        get_rep(base_airtel,token = r$j,path = apaths["events"],id = id_dand01,unixstart = 1615970883,
                unixend = as.POSIXct(Sys.time()) %>% as.integer())
     
      if(new_fuel_api_output$status_code==200) {
        ftsd <- gen_fuel_tsd(new_fuel_api_output) %>% rbind(fueldt(),.)
        #fde <- ftsd %>% add_fuel_flags() %>% get_fuel_events()
        message("\nLast 6 fuel values at:",as.character(Sys.time()),"were:")
        print(tail(ftsd))
      } else {
        message("Error in fuel level API, using old data")
        ftsd <- fueldt()
        #fde <- fuel_drain_events
      }
      if(events_omni$status_code==200) {
        atsd <- conv_ev2DT(events_omni) %>% add_ts  %>% .[type %in% api_types$code]
        cat("\nNew values of EVENTS obtained. Last value at:",as.character(Sys.time())," with EVENT type:",atsd$type %>% last,"\n")
      } else {
        message("Error in EVENT API, using old data")
        atsd <- apidt
      } 
      r$ftsd <- ftsd
      r$atsd <- atsd
      #r$fde <- fde
    })
    
    
    # new reactive variable to handle any site
    new_data <- reactive({
      tail_starts_at <- fileData()() %>% str_which(as.character(ts_last())) %>% first
      if(length(tail_starts_at)==1){
        size <- length(fileData()) - tail_starts_at
        if(size>1000) message("\nNew Data MQTT json reached: ",size,":Time to update buffer file for:",input$site)
        fileData()()[tail_starts_at: length(fileData()())] %>% proc_mqtt_topic() %>% json_split() %>% select(topic,ts,ID,TS,ST,VR)
      } else
        fileData()() %>% proc_mqtt_topic() %>% json_split() 
    })
    
    
    full_data <- reactive({
      # add projected values where DG delivered power is missing and ignition was on.
      x1 <- xmqtt()
      x2 <- new_data()
      x2 <- identify_missing(x2[ST==167],dgign = event_alerts(apidt,event_pattern = "ign")[,c(2:3)])[miss_start>100,ign_START] %>% map(~fill_missing(dt = x2[ST==167],ign_start = .x)) %>% rbindlist() %>% rbind(x2,.,fill=T)
      x3 <- rbind(x1,x2,fill=T)
      setkey(x3,ts,ID,ST)
      unique(x3,by=key(x3))
      })
    
   
    observe({
      message("\nAction button",input$sub1)
      cat("\nTotal lines in full ",input$site, " are ",nrow(full_data()))
    })
    
    DT1 <- 
      reactive(label = "DT1", {
        message("\nDT1 tail:")
        x1 <- full_data()
     
            setDT(x1)
            print(tail(x1))
            x1
    })
   
     DT4 <- 
      reactive(label = "DT4",{
        message("\nDT4 tail:")
        x1 <- rbind(r$ftsd,full_data()[ST == 159 | ST==101],fill=T)[order(ts)]
        setkey(x1,ts,rV,ID,ST)
        x1 <- unique(x1,by=key(x1))
        print(tail(x1))
        cat("\nDT4 unique rows",uniqueN(x1))
        x1
    })

  
  tsd_reactive1 <- reactive({
    #browser()
    tsd_filt(DT1(),st=input$st1,dev=input$device1,dr=input$daterange)
    })
  tsd_reactive2 <- reactive(tsd_filt(DT1(),st = input$st2,dev=input$device2,dr = input$daterange))
  tsd_reactive3 <- reactive(tsd_filt(DT1(),st = input$st3,dev=input$device3,dr = input$daterange))
  
  dy1 <- reactive({
    x1 <- setDT(tsd_reactive1())
    dygen(tsd=x1,site=input$site,device=input$device1,st=input$st1,pdt=paramdt1())
  })
  dy2 <- reactive({
    dygen(tsd=setDT(tsd_reactive2()),site=input$site,device=input$device2,st=input$st2,pdt=paramdt2())
    })
  dy3 <- reactive(dygen(tsd=setDT(tsd_reactive3()),site=input$site,device=input$device3,st = input$st3,pdt=paramdt3()))
   
  dy4 <- reactive({
    filt_tsd <- 
      r$ftsd[
      as.Date(ts,tz="Asia/Kolkata") >= input$daterange[1] & as.Date(ts,tz="Asia/Kolkata") <= input$daterange[2]
      ]
    # fix the TSD y scale and x axis ranges
    maxval <- max(filt_tsd$rV) + 5
    minval <- min(filt_tsd$rV) - 10
    if(isTruthy(filt_tsd)){
    filt_tsd %>% 
      dygraph(group = "ZZZZ",main = "DAND01 FUEL STATUS") %>% 
      dyAxis(name = "y",label = "Litres of Diesel",valueRange = c(minval,maxval)) %>% 
      dySeries(fillGraph = T,drawPoints = T,pointSize = 2,strokePattern = c(1,2),strokeWidth = 1.5,color = brewer.pal(8,"Set1")[7]) %>%
      dyRangeSelector(retainDateWindow = T) %>%
      dyOptions(titleHeight = 25)
    } else dy_nodata()
  }
  )
  
  dy_shaded1 <-  reactive({
    shade_events(DT=DT1(),dy=dy1(),flags=input$Id001,atsd=r$atsd)
  })
  
  dy_shaded2 <-  reactive({
    shade_events(DT=DT1(),dy=dy2(),flags=input$Id002,atsd=r$atsd)
  })
  
  dy_shaded3 <-  reactive({
    shade_events(DT=DT1(),dy=dy3(),flags=input$Id003,atsd=r$atsd)
  })
  
  dy_shaded4 <-  reactive({
    shade_events(DT=DT4(),dy=dy4(),flags=input$Id004,atsd=r$atsd)
  })
  
       
         output$tsd1 <-  renderDygraph({
           req(isTruthy(as.numeric( str_extract(input$st1,"\\d+")) >0))
             if(input$realtime==T) auto_refresh_invalidate()
              input$Id001; input$refresh
           isolate(dy_shaded1())
         })
         output$tsd2 <-  renderDygraph({
           req(isTruthy(as.numeric( str_extract(input$st2,"\\d+")) >0))
           if(input$realtime==T) auto_refresh_invalidate()
         input$Id002; input$refresh
           isolate(dy_shaded2())
         })
           
         output$tsd3 <-  renderDygraph({
             req(isTruthy(as.numeric( str_extract(input$st3,"\\d+")) >0))
             if(input$realtime==T) auto_refresh_invalidate()
           input$Id002; input$refresh
             dy_shaded3()
           })
        
         output$tsd4 <- renderDygraph({
           if(input$realtime==T) auto_refresh_invalidate()
            input$Id004; input$refresh
           isolate(dy_shaded4())
         })
         
         output$acwtot <- renderPlot({
           if(input$realtime==T) 
             hourly_acwh( full_data()[ts>=Sys.time() - hours(input$wtime)]) else
               hourly_acwh(isolate(full_data())[ts>=Sys.time() - hours(input$wtime)])
           })
         output$dcwtotdelta <- renderPlot({
           if(input$realtime==T) 
               hourly_dcwh( full_data()[ts>=Sys.time() - hours(input$wtime)]) else
             hourly_dcwh(isolate(full_data())[ts>=Sys.time() - hours(input$wtime)])
           })
         
         cphreport <- reactive({
           isolate({
             cph_rep((full_data()),fueldt = r$ftsd,adt = r$atsd )
           })
         })
         
         
         output$cphsum <- render_gt({
           x1 <- cphreport()
           if("lpu" %in% input$cph_filts) x1 <- x1[!is.na(LPU)]
            if("lweek" %in% input$cph_filts)  x1 <- x1[ign_START > Sys.time() - days(7)]
            if("cph" %in% input$cph_filts)  x1 <- x1[!is.na(CPH)]
          x1 %>% 
            select(starts_with("ign"),Hours,Liters,WH,CPH,`Avg.Power`,LPU) %>% 
             gt() %>% 
             fmt_number(columns = c(3:8),decimals = 2) %>% 
             tab_footnote(footnote = "Liters Per Unit of energy generated (1 Unit = 1 KWHr); LPU is the measure of efficiency of the DG set.",
                          locations = cells_column_labels(columns = "LPU")) %>% 
             fmt_missing(columns = everything(), missing_text = "-")
         })
         
         output$cphval <- renderValueBox({
           valueBox(value = cphreport()[,sum2(Liters)/sum2(Hours)] %>% round_to_fraction(denominator = 100),subtitle = "Liters Per Hour",color = "purple")
         })
         output$lpu <- renderValueBox({
           valueBox(value = cphreport()[ign_START>=ymd(20210408),sum2(Liters)*1000/sum2(WH)] %>% round_to_fraction(denominator = 100),subtitle = "Liters Per (KWH) Unit",color = "aqua")
         })
         
         output$hours <- renderValueBox({
           valueBox(value = cphreport()[,sum(Hours,na.rm = T)] %>% round_to_fraction(denominator = 100),subtitle = "Total Running Hours.",color = "olive")
         })
         
        observeEvent(input$saveDT,{
          message("\nSaving DTs in RDS")
          saveRDS(full_data(),dtfiles[Site==input$site,Filename])
          saveRDS(r$ftsd,fuelfiles[Site==input$site,Filename])
          saveRDS(r$atsd,"eventdt.RDS")
          saveRDS(vehdt,"vehiclelist.RDS")
          updateActionButton(session=session,inputId = 'saveDT',label = paste("Saved:",Sys.time() %>% format("%d-%b %H:%M")))
          cat("..SAVED")
        })
})


And a truncated global.R is here (note: have removed function bodies. Just retained the declarations.

#global.R
suppressPackageStartupMessages(library(shiny))
suppressPackageStartupMessages(library(shinydashboard))
suppressPackageStartupMessages(library(shinydashboardPlus))
suppressPackageStartupMessages(library(data.table))
suppressPackageStartupMessages(library(magrittr))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(dygraphs))
suppressPackageStartupMessages(library(shinyWidgets))
source("mqtt.R")
source("omniapi.R")
source("insights.R")

cat("\nApplication Starting. Loading data from disk")
devdt <- fread("device_codes.txt")
mqfiles <- fread("mqtt_files.txt")
dtfiles <- fread("prdata_files.txt")
vehdt <- readRDS("vehiclelist.RDS")
eventdt <- readRDS("eventdt.RDS")
api_types <- fread("omni_api_type.txt")
devfiles <- fread("topics.txt")
fuelfiles <- fread("fuel_files.txt")
cat("..loaded.")

#===== FUNCTIONS DEFINED HERE =====
sum2 <- function(x) sum(x,na.rm = T)

which_file <- function(t){..}
which_id <- function(t){..}

recurse_dyshade <- function(dyg,event_times,colorcode="#778811"){..}

dy_nodata <- function()  {..}


# to add start and end times for shading
shade_events <- function(dy,DT,flags,atsd){..}
    

tsd_filt <- function(x,st,dev,dr) {..}
    

dygen <- function(tsd,site,device,st,pdt){..}


jwt <- refresh_token(force = F) # refreshes only if one hour old

# read vehicle list if not read for more than 12 hours
if(Sys.time() - attr(vehdt,"last") > hours(24)) {
    cat("\nVehicle list is older than 24 hours therefore refreshing from Omni server")
    vehraw <- get_veh_list(url = base_airtel,token = jwt)
    if(vehraw$status == 200) {
        cat("\nSuccessfully extracted new vehicle list through API")
        vehdt <- gen_veh_dt(vehraw)
        cat("\nRead in following sites:",vehdt$name)
    } else {
        message("Error in vehicle list API")
        print(vehraw)
    }
}
currUnixtime <- as.POSIXct(Sys.time()) %>% as.integer()
message("\nFirst attempt...Getting Event from Omni server...")
events_omni <- get_rep(url = base_airtel,token = jwt,path = apaths["events"],id = id_dand01,
                       unixstart = eventdt$ts %>% last %>% as.numeric(),
                       unixend = as.integer(Sys.time())
)
if(events_omni$status_code != 200)
{
    jwt <- refresh_token(jwt,force = T)
    message("\nNext try...Getting data from Omni server, after refreshing token...")
    events_omni <- get_rep(base_airtel,token = jwt,path = apaths["events"],id = id_dand01,unixstart = 1615970883,unixend = currUnixtime)
} 

if(events_omni$status_code != 200) message("Unsuccessful EVENTS API outcome the second time !") else
    message("Successful API outcome for Fuel EVENTS !")

new_events <- conv_ev2DT(events_omni) %>% add_ts # Have to integrate both into one function
apidt <- rbind(eventdt,new_events)
setkey(apidt,ts,type)
apidt <- unique(apidt,by = key(apidt))

# end of global.R

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
Lazarus Thurston
  • 1,197
  • 15
  • 33
  • It would best to show the code if you want someone to help you. I have not seen error in situation 1 you mention above. – YBS Apr 22 '21 at 20:06
  • OK. I've added source.R and global.R. Have removed function bodies retaining the arguments in the function definitions (as that's what is needed in server.R). A huge apology for pasting the full server.R but that's exactly the problem - that I cannot narrow down to the offending lines as error message does not include the line number. – Lazarus Thurston Apr 23 '21 at 02:37

1 Answers1

1

The problem seems to be in this line

r <-  reactiveValues(ftsd=fueldt(),atsd=apidt,j=jwt)

This can be demonstrated by a small example shown below

ui <- fluidPage(
  DTOutput("t1")
)
server <- function(input, output){
  df1 <- reactive({head(mtcars)})
  
  r <-  reactiveValues(ftsd=df1())  ## reason for error
  ### uncomment next two lines to see no error (and comment the previous line)
  # r <-  reactiveValues()
  # observe({ r$ftsd <- df1() })
  
  output$t1 <- renderDT(r$ftsd)
}

runApp(shinyApp(ui, server))
YBS
  • 19,324
  • 2
  • 9
  • 27
  • Bang on @YBS ! This also clears a general concept that `reactiveValues()` cannot use a reactive variable to initialise any value. The initialisation can only have static variables. – Lazarus Thurston Apr 23 '21 at 08:52
  • 1
    @LazarusThurston, This isn't entirely true, I believe. You could have initialized `r` in a reactive context, like the expression in `observe`. This `observe(r <- reactiveValues(ftsd=fueldt(),atsd=apidt,j=jwt))` should work also. – SmokeyShakers Apr 26 '21 at 15:06