Forge tunnel / forge deploy cache issues

Hey folks,

Wondering if anyone else is experiencing this too — I’ve been running into a recurring issue when switching between forge deploy and forge tunnel.

To be honest, it’s been a bit of a nightmare. It often claims everything is deployed, but in reality, it’s still serving the old version for a while. The only way I can tell if it’s actually updated is by sneakily injecting a unique marker into each deployment — like a little breadcrumb trail. :upside_down_face:

Switching between deploy and tunnel is just as unpredictable, taking way too much time to settle down and behave. From what I can tell, it seems like Forge might be hanging onto something in its internal cache — not browser cache, but something on the platform side.

Is there a known way to force a cache clear on Forge itself? I couldn’t find anything exposed for devs.

Also, I’ve recently started seeing this error popping up frequently (even though I’ve got no iterations in the backend function), and I’m fairly sure I’m not the only one getting hit by this.

Would love any tips or war stories if you’ve dealt with something similar :folded_hands:

7 Likes

I can confirm that I’ve also often trouble switching between ‘forge deploy’ and ‘forge tunnel’. After ‘forge tunnel’ the site often seems to be stuck in the tunnel version, without a good way to disconnect it.

I the end I often seem to have to do a ‘forge deploy, forge uninstall, forge install’ cycle to get the app in a working state again. But that might be more suspicious folklore from my side. I’ll would need to keep track to know for sure.

4 Likes

exactly ! same here mate :slight_smile:
In terms of developer experience, not the greatest for sure.
We do spend i think hours a day with such miss-matches of versions, really annoying!

I’ve been seeing this regularly too. After stopping the tunnel, the app ends up in a broken state thinking it is still tunneling from my local machine.

Edit: After more than 20 minutes waiting for it to go away, I closed and reopened my browser and it started working again🤷‍♂️

3 Likes

Not gonna lie — even after deploying, you sometimes still get random versions of the app showing up. From what I’ve seen, this only affects the development environment, but it’s unpredictable.

There have been cases where an older or completely different version was served instead of the latest one.

How do I spot it? I manually log the version in the UI component after each deploy (yeah, a bit old-school, but it helps!).

console.log('Deployment version #[version number]');

Honestly, until Forge’s deployment lifecycle becomes more reliable, this little trick gives me some peace of mind.

6 Likes

I’m having the same problem. I have tried uninstalling, completely deleting the app from the developer console, re-registering, re-deploying and re-installing, and it is still hanging until I run forge tunnel.

I noticed the same thing now. I am working only with deploy, I do not use tunnel. For the last few days I noticed that it takes much more time to get the latest changes in the browser after deployment. It sometimes takes up to 5 minutes to get the newest changes. For most of the time I am confused, I am not sure, which version is available.

Once it even looked like I had a “v2 frontend” and “v1 backend”. My development experience is definitely worse for the past few days. Do you have any other advices to make it more comfortable to work with?

1 Like

There is feature request for improving Forge CLI experience regarding deployment:

For the switch from forge tunnel to forge deploy not working with the localhost tunnel error, we tested recently this script stolen from somebody on Slack, and it seems to work well:

#!/bin/bash

JSON_FILE="./myForge.json"

# ============================================================
# Utility functions
# ============================================================

load_config_from_json() {
  if [[ -f "$JSON_FILE" ]]; then
    echo "ℹ️  Loading configuration from $JSON_FILE..."
    USER=$(jq -r '.USER' "$JSON_FILE")
    TOKEN=$(jq -r '.TOKEN' "$JSON_FILE")
    FORGE_APP_ID=$(jq -r '.FORGE_APP_ID' "$JSON_FILE")
    FORGE_ENVIRONMENT=$(jq -r '.FORGE_ENVIRONMENT' "$JSON_FILE")
  else
    echo "⚠️  No $JSON_FILE file found. Falling back to defaults and CLI args."
  fi
}

parse_cli_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --app)
        FORGE_APP_ID="$2"
        shift 2
        ;;
      --user)
        USER="$2"
        shift 2
        ;;
      --token)
        TOKEN="$2"
        shift 2
        ;;
      --env)
        FORGE_ENVIRONMENT="$2"
        shift 2
        ;;
      *)
        echo "❌ Unknown option: $1"
        exit 1
        ;;
    esac
  done
}

validate_inputs() {

  if [[ -z "$FORGE_APP_ID" || -z "$FORGE_ENVIRONMENT" ]]; then
    echo "❌ --app and --env parameters are required"
    exit 1
  fi

  if [[ -z "$USER" || -z "$TOKEN" ]]; then
    echo "❌ --user and --token parameters are required"
    exit 1
  fi
}

build_graphql_request() {
  flatquery='
    mutation forge_cli_deleteApplicationTunnels($input: DeleteAppTunnelInput!) {
      deleteAppTunnels(input: $input) {
        success
        errors {
          message
          extensions {
            errorType
            statusCode
          }
        }
      }
    }'
  onelinequery="$(echo $flatquery)"

  flatvars='{
    "input": {
      "appId": "ari:cloud:ecosystem::app/'$FORGE_APP_ID'",
      "environmentKey": "'$FORGE_ENVIRONMENT'"
    }
  }'
  onelinevars="$(echo $flatvars)"

  fullrequest="{ \"query\": \"$onelinequery\", \"variables\": $onelinevars }"
}

execute_graphql_call() {
  curl -H 'Content-Type: application/json' \
     -H "Authorization: Basic $(echo -n "$USER:$TOKEN" | base64)" \
     -X POST -d "$fullrequest" \
     https://developer.atlassian.com/gateway/api/graphql
}

# ============================================================
# Main
# ============================================================

FORGE_APP_ID="${FORGE_APP_ID:-}"
FORGE_ENVIRONMENT="${FORGE_ENVIRONMENT:-default}"

load_config_from_json
parse_cli_args "$@"
validate_inputs
build_graphql_request
execute_graphql_call

Thanks. It turns out my problem was mostly due to my static custom ui code not being deployed correctly, so it only worked when I was using the tunnel. Now that I’ve fully migrated to Custom UI, I’m not sure if forge tunnel is that useful since I need to do a build each time anyway.