Find your exact symptom and follow the targeted fix. Each scenario explains why it happens and the shortest path to resolution.
Use this page if you've built to the Quest successfully before and now ONE specific thing is going wrong (a particular error message, a specific visual problem, controllers not working, etc.).
Use the Step-by-Step Guide if you've never built to the Quest before, or if you're not sure what's wrong and want to check every setting from the start.
core-for-system-modules.jar and a path inside C:\Program Files\Unity\C:\Program Files\Unity\. On school computers, that folder is locked so it can't be changed. The build process tries to modify a file there and fails because it doesn't have permission.Open Player Settings → Other Settings → Target API Level.
Change it from Android 16 (API 36) to Android 14 (API 34) or Android 15 (API 35).
Delete the cache folder at C:\Users\[your-username]\.gradle\caches\ and try building again.
Download Android Studio and install its SDK to a folder you have permission to write to: C:\Users\[you]\AppData\Local\Android\Sdk.
Point Unity to it: Edit → Preferences → External Tools → Android SDK. Uncheck "Unity bundled" and browse to the new folder.
Delete BOTH of these folders:
C:\Users\[you]\.gradle\caches\Library\Bee\Note: The build keeps a copy of broken work in these caches. Even if you fix the original problem, the cache will keep using the broken version until you delete it.
Download Android Studio. During installation, accept the default SDK location: AppData\Local\Android\Sdk.
In Android Studio's SDK Manager, install: SDK Platform 34 or 35, Build-tools 36.0.0, Command-line tools 16, and NDK r27c.
Uncheck "Android SDK Tools Installed with Unity (Recommended)" and set the path to your new SDK folder.
Do the same for NDK: uncheck "Installed with Unity" and set the path to AppData\Local\Android\Sdk\ndk\27.2.12479018.
Open Edit → Preferences → External Tools.
Make sure "JDK Installed with Unity (Recommended)" IS checked.
Note: Unity 6.3 comes with JDK 17 built in. Use it unless you have a specific reason not to.
Delete the folder Library\Bee\ inside your Unity project.
This forces Unity to recompile everything from scratch with the correct JDK.
Open Command Prompt and run:
The result should say device, NOT unauthorized.
If it says unauthorized: put on the headset, look for the "Allow USB Debugging" popup, check "Always allow from this computer," and click Allow. Then run the command again.
Find the APK file Unity created (in the folder you chose during Build Settings). Then run this in Command Prompt:
Replace the path with where your APK actually is. The -r means "replace if already installed."
Put the headset on. Open the App Library.
At the top right of the library, tap the filter dropdown and select Unknown Sources.
Note: Apps you build yourself only show up in this filtered view, not in the main library where store apps appear.
On your phone, open the Meta Horizon app. Tap on your headset, then tap "Developer Mode."
The toggle must be ON.
Note: Without Developer Mode, the headset refuses to install apps that didn't come from the store.
Check the box next to Meta Quest Support. Rebuild and reinstall.
Open Player Settings → Android tab → Icon and upload an image to use as your app's icon.
Note: Even with everything correct, if you don't upload an icon, Unity will always use its default cube. So an icon that LOOKS wrong might just mean you never added one.
Check the box next to Meta Quest Support.
Click the gear icon next to it and check Quest 3S (and Quest 3) under Target Devices.
In the same OpenXR settings, find the Interaction Profiles section.
Click + and add Meta Quest Touch Plus Controller Profile.
Note: Without a controller profile, the VR session can't fully start up.
Click Fix All to fix any red errors. Then rebuild and reinstall.
Set Render Mode to Multi-view.
Note: "Multi-pass" mode often shows a black screen on the Quest 3S. Multi-view is the safer choice.
Click on your Main Camera in the Hierarchy. In the Inspector, find the Tracked Pose Driver component.
Both inputs must be bound:
centerEyePosition [XR HMD]centerEyeRotation [XR HMD]Note: If either is empty or set to a keyboard/mouse input, the camera won't follow the headset — it stays at a fixed point that's often inside geometry, showing black.
Set to Linear.
Note: The older "Gamma" color mode combined with OpenGLES + OpenXR creates a black screen on the headset.
Remove Vulkan from the list and add OpenGLES3. Rebuild.
If your app now works, you've confirmed Vulkan was the problem.
Click "Update" if a newer version is available.
After updating, switch back to Vulkan and try again.
In Graphics APIs settings, uncheck Auto Graphics API and list only Vulkan (or only OpenGLES3).
Note: Auto mode can pick a graphics system that doesn't work on the Quest.
Your Hierarchy must contain this structure:
If you only have a plain Camera, delete it and add an XR Origin by right-clicking in the Hierarchy → XR → XR Origin (VR).
Click on XR Origin in your Hierarchy. Look at its position in the Inspector.
Note: If XR Origin is at Y=0 and you have a floor mesh also at Y=0, the camera starts inside the floor — which looks black. Move XR Origin to Y=1.6 (about eye height).
Find your Universal Renderer Data asset (search the Project for t:UniversalRendererData).
Set Intermediate Texture to Auto and turn OFF Post Processing.
Note: Effects like Bloom often cause black screens on Quest because they use image formats the headset doesn't support.
Your scene must be in the "Scenes In Build" list AND have a checkmark.
Note: If only an empty default scene is built, you'll see a black screen with no errors at all.
Check the box next to Meta Quest Support. Rebuild and reinstall.
If you have a file at Assets/Plugins/Android/AndroidManifest.xml, open it and make sure it contains:
A custom manifest overrides the one Unity generates, so it needs the VR tag added by hand.
In Command Prompt, run (replace with your actual package name):
Then install the new build.
Note: Sometimes old settings stick around when you update an app in place. A clean reinstall makes sure all the new settings take effect.
Change Render Mode from Multi-pass to Multi-view.
Open your Universal Renderer Data asset and uncheck Post Processing → Enabled.
If the second eye fixes itself, a post-processing effect was the cause. Turn the effects back on one at a time to find which one is broken.
If you wrote any custom HLSL shaders, they need the macros UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX and UNITY_VERTEX_OUTPUT_STEREO to work with Multi-view.
Note: Built-in URP shaders already have these. This only matters if you wrote your own.
Set to Linear.
Note: When you change this, Unity will re-import all your textures. This takes several minutes the first time, but it's normal — don't interrupt it.
In your URP Asset, turn off HDR.
Note: HDR can make scenes look wrong on Quest unless you configure it specifically for the headset's display. If you don't have a reason to use HDR, leave it off.
Click on your Main Camera in the Hierarchy. In the Inspector, find the Tracked Pose Driver (Input System) component.
Both inputs must be bound to these specific actions:
centerEyePosition [XR HMD]centerEyeRotation [XR HMD]Note: If the bindings point to devicePosition or deviceRotation instead of centerEye, head movement may not register correctly. Use the centerEye versions.
Look at your Hierarchy. Your Main Camera must be a child of XR Origin, not floating at the top of the Hierarchy:
Note: If the camera is outside the XR Origin, it gets head position data but doesn't get rotated by the XR system. Drag the Main Camera into Camera Offset to fix it.
Sometimes a camera ends up with TWO Tracked Pose Driver components — one from the old XR Legacy Input system and one from the new Input System.
On the Main Camera, check the Inspector for any duplicate components. If you see both Tracked Pose Driver AND Tracked Pose Driver (Input System), right-click the older one and Remove Component. Keep only the Input System version.
Click on the XR Origin in your Hierarchy.
In the Inspector, find the Tracking Origin Mode setting. Set it to Floor for room-scale VR, or Device for seated experiences.
Note: If this is set to "Not Specified" or left at default, the headset may not provide tracking data correctly.
Put the headset on. If you see a message about setting up a play boundary or Guardian, you must complete that setup before tracking works in apps.
Move to an area with good lighting and a clear floor. The Quest needs to see its surroundings to track your head position.
Note: The Quest 3S uses cameras to track head movement. In very dark rooms or completely featureless rooms (like a closet with bare white walls), tracking can fail or stop updating.
In Command Prompt, run this WHILE launching the app:
Open crash_log.txt on your Desktop. Press Ctrl+F and search for FATAL EXCEPTION or NullReferenceException.
The lines just ABOVE the error name your script and the line that crashed.
The #1 cause is a script trying to use something that doesn't exist yet. This includes calls to GetComponent(), FindObjectOfType(), or accessing a serialized field you forgot to set in the Inspector.
Find the script named in the crash log and check the Inspector — make sure every field that has an arrow or slot is filled in.
If your Unity build log showed "Couldn't create a Convex Mesh" warnings, those mesh objects could be crashing physics when the scene loads.
In each mesh's import settings (or on its MeshCollider component), simplify the mesh or turn OFF Convex.
On your phone, open the Meta Horizon app.
Tap your headset, then tap Developer Mode. Turn the toggle ON.
Restart your headset after turning it on.
Developer Mode requires your Meta account to belong to a developer organization.
Visit developer.oculus.com and create or join an organization. You may need to add a phone number to your account to verify it.
Under Interaction Profiles, add Meta Quest Touch Plus Controller Profile.
Note: This profile is specifically designed for the Quest 3S controllers.
In your Hierarchy, click on the Left Hand and Right Hand controller objects under XR Origin.
On each one, find the XR Controller component. Make sure Position Action points to a real input action like XRI LeftHand/Position, not an empty or missing one.
Open Edit → Project Settings → Input System → Default Input Actions.
Make sure the XRI Default Input Actions asset is set there.
Note: If this is missing or set wrong, all controller tracking breaks on the headset.
Search your Hierarchy for XRInteractionManager.
If it's missing, create an empty GameObject and add the XR Interaction Manager component to it.
Note: Without this, no interaction events will fire — controllers can move, but nothing they touch will respond.
Each object you want to grab needs an XR Grab Interactable component (or XR Simple Interactable for trigger zones).
Each object also needs a Collider. Without one, the controller's ray can't detect the object.
On the XR Ray Interactor (on your controllers) AND on the XR Grab Interactable (on the object), find the Interaction Layer Mask setting.
Both must share at least one common layer.
Note: If the layers don't match, the controller will look right through the object as if it isn't there.
Unity version: In the Unity Hub, look next to your project name. Or inside Unity, click Help → About Unity.
OpenXR Plugin version: Open Window → Package Manager. Click "In Project" in the dropdown at the top. Find "OpenXR Plugin" in the list and click it. The version is shown on the right.
XR Interaction Toolkit version: Same as above, but find "XR Interaction Toolkit" in the list.
Quest headset OS version: Put the headset on. Go to Settings → System → Software Update. Your current version is shown at the top.
discussions.unity.com) — most problems have been solved by someone else already.
Ctrl + P) before starting if you'll be working away from your computer. All expanded sections will be included in the printout.