メインコンテンツまでスキップ

Local debugging guide for Extend apps

Last updated on April 8, 2026

Overview

This guide covers the debugging concepts and tools that are common to all AccelByte Extend app types — Extend Override, Extend Event Handler, and Extend Service Extension.

Use this as a baseline reference. For details specific to your app type or language, use the navigation table below.


By app type

App typeSpecific debugging guide
Extend OverrideComing soon
Extend Event HandlerComing soon
Extend Service ExtensionLocal debugging guide for Extend Service Extension

By language

LanguageLanguage setup guide
GoGo
C#C#
JavaJava
PythonPython

Environment setup

Every Extend app reads its configuration from environment variables. A template file is provided in the repository root.

Step 1 — Create your .env file

cp .env.template .env

Then open .env in your editor and fill in the values.

VS Code shortcut

The repository ships with a VS Code task called "Create .env File" (see .vscode/tasks.json). If you have fillenv installed, this task can populate the file for you automatically.

Step 2 — Fill in the required variables

The following variables are required by every Extend app type:

# AccelByte environment
AB_BASE_URL=https://<your-ags-environment>.accelbyte.io
AB_CLIENT_ID=<your-client-id>
AB_CLIENT_SECRET=<your-client-secret>

# Disable token validation during local development.
# Deployed Extend apps always have this value set to `true` and can't be changed.
PLUGIN_GRPC_SERVER_AUTH_ENABLED=false

# Log verbosity: debug | info | warn | error
LOG_LEVEL=debug
VariablePurposeExample
AB_BASE_URLYour AGS environment URLhttps://dev.accelbyte.io
AB_CLIENT_IDOAuth client IDabc123
AB_CLIENT_SECRETOAuth client secrets3cr3t
PLUGIN_GRPC_SERVER_AUTH_ENABLEDfalse to skip token checks locallyfalse
LOG_LEVELLog verbositydebug
App type-specific variables

Some app types require additional variables. For example, Extend Service Extension requires BASE_PATH. See the app type-specific debugging guide for the complete variable list.

Step 3 — Confirm the service can reach AGS

curl "$AB_BASE_URL/iam/v3/public/config"

A JSON response confirms the URL is reachable. An error here means the URL is wrong or unreachable.


Running the service locally

From VS Code

Use Terminal → Run Task → "Run: Service". This task is defined in .vscode/tasks.json and loads the .env file automatically.

Confirming the service is up

Once the service starts you should see log output similar to:

{"time":"...","level":"INFO","msg":"app server started"}

For the exact terminal run command for your language, see the language-specific guide.


Attaching the debugger in VS Code

The repository ships with a ready-to-use launch configuration in .vscode/launch.json.

  1. Make sure your .env file is filled in.
  2. Open the Run and Debug panel — press Ctrl+Shift+D (Windows/Linux) or Cmd+Shift+D (macOS), or click the bug icon in the Activity Bar.
  3. Select "Debug: Service" from the dropdown at the top of the panel.
  4. Press F5 (or click the green ▶ button).

VS Code starts the service inside the debugger. You can now pause execution, inspect variables, and step through code line by line.

For language-specific launch configuration details and non-VS Code setups, see the language-specific guide.


Setting breakpoints and inspecting state

How to set a breakpoint

Click in the gutter — the narrow strip to the left of the line numbers — next to the line you want to pause on. A red circle appears. When execution reaches that line, VS Code pauses and shows you:

  • Variables — all local variables and their current values.
  • Watch — expressions you add manually to monitor continuously.
  • Call Stack — every function call that led to the current line.
  • Debug Console — a prompt where you can evaluate expressions live.

Stepping through code

ActionShortcutWhat it does
ContinueF5Run until the next breakpoint
Step OverF10Execute the current line without entering any function it calls
Step IntoF11Enter the function called on the current line
Step OutShift+F11Finish the current function and return to the caller
RestartCtrl+Shift+F5Restart the debug session
StopShift+F5Stop the debugger

Conditional breakpoints

Right-click a breakpoint circle → Edit Breakpoint → type a condition. The debugger only pauses when the condition evaluates to true. This is especially useful when you want to inspect only a specific request out of many.

For condition syntax examples in each language, see the language-specific guide.

Tips

  • Read the Call Stack panel. When the debugger pauses, the Call Stack shows every function call that led to the current line — from the current frame down to the entry point. This tells you exactly how a request arrived at your code.

  • Use the Watch panel. Add expressions like req.Namespace or err so you can monitor them as you step, without re-expanding the Variables panel at every line.

  • Use conditional breakpoints. Rather than stopping on every request, narrow the condition to the exact input you are investigating.


Reading and understanding logs

Every Extend app emits structured JSON log lines to stdout. A single log line looks like:

{"time":"2026-03-10T12:00:00Z","level":"INFO","msg":"request received","method":"SomeMethod","duration":"1.234ms"}

Log levels

LevelWhen it appearsWhen to pay attention
DEBUGOnly when LOG_LEVEL=debugFine-grained tracing of logic and variable values
INFODefaultNormal events (server started, request received)
WARNSomething unexpected but non-fatalWorth investigating if it appears repeatedly
ERRORSomething failedAlways investigate

Always set LOG_LEVEL=debug in your .env during local development. The extra gRPC payload logs often reveal the problem without needing a breakpoint at all.

gRPC request/response pairs

The service automatically logs the start and finish of every gRPC call:

{"msg":"started call","grpc.method":"SomeMethod", ...}
{"msg":"finished call","grpc.code":"OK","grpc.duration":"2ms", ...}

If grpc.code is anything other than OK — for example Unauthenticated, Internal, or NotFound — scroll up in the logs to find the ERROR line that explains why.

Pretty-printing logs with jq

Install jq and pipe the service output through it during local development:

# Pretty-print all logs
<your-run-command> 2>&1 | jq '.'

# Show only ERROR-level logs
<your-run-command> 2>&1 | jq 'select(.level == "ERROR")'

Replace <your-run-command> with the language-specific command from the language guide.


Testing with grpcurl

grpcurl lets you call the gRPC server on port 6565 directly. Every Extend app exposes a gRPC server on this port.

# List available services (server reflection is enabled)
grpcurl -plaintext localhost:6565 list

# Call a method directly
grpcurl -plaintext \
-d '{"namespace":"mygame"}' \
localhost:6565 <ServiceName>/<MethodName>

This is useful for isolating whether a problem is in the app logic or in a higher-level gateway layer.

When PLUGIN_GRPC_SERVER_AUTH_ENABLED=true, add a valid bearer token in the gRPC metadata:

grpcurl -plaintext \
-H "authorization: Bearer <token>" \
-d '{"namespace":"mygame"}' \
localhost:6565 <ServiceName>/<MethodName>

Common issues

Service exits — "unable to login using clientId and clientSecret"

Symptom:

{"level":"ERROR","msg":"error unable to login using clientId and clientSecret","error":"..."}

Cause: AB_CLIENT_ID or AB_CLIENT_SECRET is wrong, or AB_BASE_URL points to the wrong environment.

Fix:

  1. Double-check the credentials in your .env.
  2. Confirm AB_BASE_URL is reachable: curl "$AB_BASE_URL/iam/v3/public/config".
  3. Make sure your OAuth client has the CLIENT_CREDENTIALS grant type enabled in the Admin Portal.

All requests return 401 Unauthenticated

Symptom: Every gRPC call returns status Unauthenticated.

Cause: Token validation is enabled and the bearer token in your request is missing, expired, or lacks the required permission.

Fix (local debugging): Set PLUGIN_GRPC_SERVER_AUTH_ENABLED=false in .env and restart.


Breakpoints are never hit

Possible causes and fixes:

CauseFix
The request fails before reaching your code (e.g., at auth)Disable auth: PLUGIN_GRPC_SERVER_AUTH_ENABLED=false
Another instance of the service is running on the same portCheck for port conflicts: ss -tlnp | grep 6565 and stop the stale process
The code path is not reached (wrong method name)Confirm available methods: grpcurl -plaintext localhost:6565 list

Tips and best practices

  • Always use LOG_LEVEL=debug locally. The extra gRPC payload logs often reveal the problem without needing a breakpoint at all.

  • Disable auth locally; re-enable it before you commit. PLUGIN_GRPC_SERVER_AUTH_ENABLED=false is a development shortcut — not a permanent setting. Before pushing, set it back to true and verify your token permissions still work.

  • Check ports before starting. If you see "address already in use", a previous instance of the service is still running:

    ss -tlnp | grep 6565

    Kill the stale process and start again.

  • Never commit your .env file. It contains credentials. Confirm it is listed in .gitignore. Do commit changes to .env.template so teammates know what variables are needed.


Debugging with AI assistance

Optional section

If your team does not use AI tooling, skip this section. Every other section in this guide is fully self-contained.

AI coding assistants such as Claude Code, GitHub Copilot, and others can help explain unfamiliar code, parse logs, and suggest targeted fixes.

Effective prompting tips

Paste the full error, not just the symptom.

Instead of: "Why does my service crash?"

Try: "My Extend app exits at startup with the following log. What is the most likely cause and how do I fix it?"

{"level":"ERROR","msg":"error unable to login using clientId and clientSecret","error":"401 Unauthorized"}

Include the relevant source file.

"Here is my service implementation file. The method returns codes.Internal for a specific input. Should I handle this case separately?"

Ask for an explanation before a fix.

"Explain what PLUGIN_GRPC_SERVER_AUTH_ENABLED does and why it is safe to disable during local development."

MCP servers

The app templates ship with Model Context Protocol (MCP) server configurations in .vscode/mcp.json that give AI assistants direct access to AccelByte-specific knowledge:

ServerWhat it provides
ags-extend-sdk-mcp-serverKnowledge of AccelByte Extend SDK symbols, types, and usage patterns
ags-api-mcp-serverLive AGS REST API access (requires AB_BASE_URL in your environment)

References