📁 Sangam Dhakal - Portfolio v2.0 - Netscape Navigator 4.0
_
□
×

📚 Interview question

The IDE shows red squiggles and IntelliSense errors, but `dotnet build` succeeds. How do you diagnose and fix it?

Diagnosing mismatches between IDE diagnostics and the real build: design-time builds, SDK resolution and global.json, stale caches, restore problems, source generators and multi-targeting.

Mid-Level Debugging Intermediate design-time-build global-json ide intellisense troubleshooting

🎯 Key points

  • IDE diagnostics come from design-time builds and the language service, not the real build
  • Filter the Error List to Build only vs IntelliSense only (or check the VS Code Problems panel and C# output) to see which side reports the error
  • Compare the SDK the IDE resolved with `dotnet --version` and global.json
  • Check project configuration: wrong or conditional references, the wrong solution or project context loaded
  • Clear stale state: obj/ folders, .vs/, Rider caches, or restart the language server; a restart can fix a one-off glitch but recurring cases need a root cause
  • Check restore: missing or outdated obj/project.assets.json breaks IntelliSense first
  • Source generators and multi-targeting can show different results per target framework
  • Fix the root cause in the repo and verify with a clean CLI build and a binary log

⏱ 30-second answer

The IDE's errors come from design-time builds and the language service, not from the real compiler run, so a mismatch means the IDE has a different view of the project. I first confirm which side reports the error by filtering the Error List to Build only and IntelliSense only. Then I check the usual causes: the IDE resolved a different SDK from the CLI (fix with global.json), stale caches in obj/ or .vs/, a failed restore, a source generator that has not re-run, or the wrong target framework context in a multi-targeted project. I fix the root cause and confirm with a clean dotnet build.

🗣 Full answer (senior)

How I would answer this in an interview

"IntelliSense errors come from design-time builds and the language service, not from the real compiler run, so a mismatch means the IDE has a different view of the project. I first prove which side is wrong by filtering the Error List to Build only and IntelliSense only; a restart is fine once for a glitch, but the mistake I see is treating it as the fix when the errors keep coming back. Then I work through the causes in order: the IDE resolving a different SDK from dotnet --version and global.json, a failed restore with no obj/project.assets.json, stale obj/ and .vs/ caches, conditional references or the wrong solution loaded, and finally source generators or the wrong target framework context in a multi-targeted project.

For example, after we moved [our order-processing service] to .NET 10, CI was green but [about half the team] had IntelliSense errors on the new C# 14 code. I had to find out why the IDE and CI disagreed and stop it happening again. I used the Error List filter to show the errors were IntelliSense-only, compared dotnet --version with each developer's IDE version, and found they were still on Visual Studio 2022, which doesn't support .NET 10. I moved everyone to Visual Studio 2026 or a current Rider, added global.json to pin the SDK, and documented minimum IDE versions. The phantom errors were gone [within a day], and we had no repeat on the next upgrade.

When anything is still unclear, I verify with a clean clone and dotnet build -bl, because the binary log shows exactly which SDK, properties and targets MSBuild used. A recurring IDE-versus-CLI mismatch is a repository defect, so the fix belongs in the repo, not in everyone deleting their .vs folders."


1. Confirm which side is wrong

  • Visual Studio: in the Error List, switch the filter between Build + IntelliSense, Build only and IntelliSense only. If the error disappears under Build only, it is a design-time problem.
  • VS Code: errors in the Problems panel come from the language server; look at View → Output → C# for load failures.
  • Rider: errors in the editor come from its analysis engine; a real build's output appears in the Build window.

2. Try the cheap fix once, then look for a cause

A restart of the IDE or language server can clear a transient glitch, such as a language server that crashed during a branch switch or a large merge. That is a reasonable first move. If the errors come back, or several people see them, there is a real cause in the environment or the repo and the steps below find it.

3. Check the SDK and tool versions

Run dotnet --version in the repo folder; it honours global.json. If the IDE is older than the SDK the repo needs (for example Visual Studio 2022 against a net10.0 project that uses C# 14), the language service will not understand new syntax even though the CLI build works. Pin the SDK in global.json and make sure everyone runs an IDE that supports it.

4. Check project configuration

  • A PackageReference or ProjectReference with a Condition (for example on $(Configuration) or an environment variable) can be present in the CLI build and missing in the IDE's evaluation, or the other way round.
  • References added by hand with a HintPath to a DLL outside the repo work on one machine only.
  • The IDE may have loaded a different solution from the one you build. In VS Code, dotnet.defaultSolution decides which solution C# Dev Kit loads when a folder has several.

5. Clear stale state

  • Close the IDE and delete obj/ folders (and bin/ if needed).
  • Visual Studio: delete the hidden .vs/ folder. Rider: File → Invalidate Caches. VS Code: run .NET: Restart Language Server or Developer: Reload Window.
  • Run dotnet build-server shutdown to stop compiler and MSBuild server processes holding old state.

6. Check restore

IntelliSense needs obj/project.assets.json. If a private NuGet feed needs credentials the IDE does not have, the CLI may restore fine while the IDE fails. Run dotnet restore and check the IDE's restore output.

7. Source generators and multi-targeting

  • Generated code may be stale in the IDE until a rebuild or language server restart.
  • In a project with <TargetFrameworks>net8.0;net10.0</TargetFrameworks>, the editor shows errors for the selected project context (the dropdown at the top-left of the Visual Studio editor). An API that only exists in net10.0 shows as an error in the net8.0 context. That is correct behaviour and needs #if NET10_0_OR_GREATER or a different API.

8. Verify

Build from a clean clone with dotnet build -bl and inspect the binary log in the MSBuild Structured Log Viewer if anything is still unclear.

Production example

After upgrading a service to .NET 10, several developers saw squiggles under C# 14 extension members while CI was green. Their machines had no global.json constraint and still ran Visual Studio 2022. We added global.json, moved the team to Visual Studio 2026, and documented the minimum Rider version.

🔍 What the interviewer is checking

The interviewer is checking whether you understand that the IDE and the build are separate pipelines, and whether you troubleshoot methodically.

Green flags

  • Mentions design-time builds and the Error List filter.
  • Checks SDK resolution and global.json.
  • Knows multi-targeting project contexts and source generator staleness.
  • Fixes the cause in the repository.

Red flags

  • Only "restart and clear caches".
  • Blames the IDE without evidence.
  • Has never used a binary log.

📚 Learn in depth

1. Two different builds

                 +----------------- IDE ------------------+
 .csproj ------> | design-time build                      |
 (+ Directory.   |  evaluate properties/items             |
  Build.props)   |  run selected targets (resolve refs)   |--> language service --> squiggles
                 |  results cached (.vs/, Rider caches)   |
                 +----------------------------------------+
 .csproj ------> dotnet build: restore -> full target graph -> csc --> real errors and outputs

A design-time build runs a subset of MSBuild targets to answer "which source files, references, analysers and compiler options does this project have?" without compiling to disk. It runs once per project and per target framework, its results are cached, and the language service builds its compilation model from them.

Design-time build Real build (dotnet build)
Purpose Feed IntelliSense and analysis Produce DLLs
Targets run A subset (resolve references, collect compile items) The full graph, including CoreCompile
Writes outputs No Yes, to bin/ and obj/
Triggered Opening the solution, changing a project file, switching branches When you build
Cached Yes, by the IDE Incremental on disk

Anything that makes these two views differ produces phantom errors (errors only the IDE shows) or missing ones.

2. The usual causes, and how to tell them apart

Cause How it shows How to confirm
IDE older than the SDK or C# version New syntax underlined, CLI fine Compare the IDE version with what .NET 10/C# 14 needs; dotnet --version in the repo
Different SDK in IDE and CLI Random differences after an SDK install dotnet --info in the repo folder; the IDE's toolset setting
Failed or partial restore Missing types from packages, everything red Missing or stale obj/project.assets.json; IDE restore output
Stale caches Errors persist after a fix or a branch switch Errors vanish after deleting .vs/ or invalidating caches
Wrong project context (multi-targeting) API errors only for one framework Switch the editor's project-context dropdown
Source generator not re-run Generated members "missing" Dependencies → Analyzers → (generator) shows old output
Conditional references or build-only targets IDE misses files or references Binary log of a design-time build
Wrong solution loaded Projects missing from Solution Explorer Title bar, Solution Explorer root, dotnet.defaultSolution in VS Code

3. Why custom targets cause this

A target in Directory.Build.targets that generates source files only during a full build (for example BeforeTargets="CoreCompile" with a condition that skips design-time builds) means the IDE never sees those files. The real build compiles fine; the IDE complains about missing types.

MSBuild sets DesignTimeBuild=true (and Visual Studio sets BuildingInsideVisualStudio=true) during IDE evaluations. Conditions on those properties are a common culprit when you search the build files. The fix is to produce generated code with a source generator, or to make the generating target run in design-time builds too.

4. Multi-targeting and project contexts

With <TargetFrameworks>net8.0;net10.0</TargetFrameworks>, the IDE analyses each framework separately but shows errors for the selected context (the dropdown at the top-left of the Visual Studio editor, or the equivalent in Rider). An API that exists only in net10.0 is a real error in the net8.0 context. The fix is #if NET10_0_OR_GREATER or a different API, not ignoring the squiggle.

5. Capturing a design-time build log

  • Visual Studio: install the Project System Tools extension, then View → Other Windows → Build Logging records design-time builds as binary logs.
  • Any IDE: set the environment variable MSBUILDDEBUGENGINE=1 before starting the IDE; MSBuild writes binary logs of every build, including design-time ones, to an MSBuild_Logs folder.
  • Open the logs in the MSBuild Structured Log Viewer and compare the properties, items and references with those of a dotnet build -bl log.

Turn MSBUILDDEBUGENGINE off afterwards; it writes a lot of files and the logs can contain environment variables and paths.

6. A systematic order

  1. Confirm which side reports the error (Error List filter, Problems panel, Rider's build window).
  2. Restart the language service once for a one-off glitch.
  3. Check the SDK and IDE versions.
  4. Check restore.
  5. Clear caches.
  6. Check project context, generators and conditional build logic.
  7. Verify with a clean clone and dotnet build -bl.

7. Performance considerations

Slow design-time builds are also why large solutions feel sluggish. Heavy custom targets, many target frameworks and very large project counts all multiply design-time work. Solution filters and fewer target frameworks help.

8. Try it yourself

  1. Create a project with <TargetFrameworks>net8.0;net10.0</TargetFrameworks>.
  2. Call an API added in .NET 10 and switch the editor's project context between frameworks; watch the error appear and disappear.
  3. Wrap the call in #if NET10_0_OR_GREATER and confirm both contexts are clean.
  4. Add a target with Condition="'$(DesignTimeBuild)' != 'true'" that adds a generated .cs file, and see the IDE miss it while the build passes.
  5. Run dotnet build -bl and open msbuild.binlog in the MSBuild Structured Log Viewer.

💻 Code

Diagnostic commands, run from the repo root:

dotnet --version            # SDK chosen for this folder (honours global.json)
dotnet --list-sdks          # SDKs installed on this machine
dotnet build-server shutdown
dotnet restore --force
dotnet build -bl            # writes msbuild.binlog for the Structured Log Viewer

Remove build output folders (bash; review before running):

find . -type d \( -name bin -o -name obj \) -prune -exec rm -rf {} +

Pin the SDK so the IDE and CLI agree, in global.json at the repo root:

{
  "sdk": {
    "version": "10.0.100",
    "rollForward": "latestFeature"
  }
}

Handling an API that only exists in one target framework:

namespace Orders.Domain;

public static class Hashing
{
    public static string Sha256Hex(byte[] data)
    {
#if NET10_0_OR_GREATER
        return Convert.ToHexStringLower(System.Security.Cryptography.SHA256.HashData(data));
#else
        return Convert.ToHexString(System.Security.Cryptography.SHA256.HashData(data)).ToLowerInvariant();
#endif
    }
}

⚠ Common mistakes

  • Mistake: making "restart Visual Studio" the whole fix for a recurring problem. A restart clears a one-off glitch, but if the errors come back it hides a real cause in the environment or the repo, and everyone keeps losing time. Instead: restart once; if it recurs, work through SDK, restore, caches and project configuration, and fix the cause in the repo.

  • Mistake: loading the wrong solution. If a folder has several solutions, the IDE may load one that doesn't contain the project you're editing, so its references look missing. Instead: check the title bar and Solution Explorer root in Visual Studio, the Solution view in Rider, and set "dotnet.defaultSolution": "Orders.slnx" in .vscode/settings.json for VS Code.

  • Mistake: overlooking IDE settings that change what is analysed. With full-solution analysis off, errors in closed files don't show; an Error List filter left on hides build errors. Instead: check the Error List filter and the analysis scope before concluding the IDE and CLI disagree.

  • Mistake: ignoring NuGet version differences. A version that comes from a property, a Condition or a floating range (1.*) can resolve differently in the IDE's restore and the CLI's. Instead: compare dotnet list package --include-transitive with obj/project.assets.json, and pin versions centrally with Central Package Management.

  • Mistake: running git clean -xdf blindly. It deletes every untracked file, including local configuration and work in progress. Instead: delete only bin/, obj/ and the IDE cache folder, or run git clean -xdn first to preview what would be removed.

  • Mistake: ignoring the project context dropdown in multi-targeted projects. With net8.0 selected you see errors for APIs that exist only in net10.0, and miss errors that occur only in net10.0. Instead: switch context to each framework, and rely on the CLI build, which compiles every target.

  • Mistake: not pinning the SDK. Each machine resolves whatever SDK is newest, so the IDE and the CLI can use different compilers. Instead: commit a global.json and check dotnet --version in the repo folder.

  • Mistake: assuming CI is wrong when it disagrees with the IDE. CI builds from a clean clone, so it's usually the more trustworthy result. Instead: reproduce the CI result locally with a clean clone and dotnet build -bl before blaming the pipeline.

  • Mistake: generating code in custom targets that only run in full builds. The IDE never sees the generated files or references, so it reports missing types. Instead: use a source generator, or make the target run in design-time builds too. Check generated files under Dependencies → Analyzers, and set EmitCompilerGeneratedFiles to true to compare them with the build output.

🏛 Senior insight: trade-offs

A senior engineer treats a recurring IDE-versus-CLI mismatch as a repository defect, not a personal annoyance. The fix belongs in the repo: global.json, a documented minimum IDE version, source generators instead of build-only code generation, and a CI build from a clean clone. Every minute developers spend deleting .vs folders is lost delivery time across the whole team.

Use evidence, not guesswork: the Error List filter tells you which side is wrong in seconds, and a binary log (-bl) shows exactly which SDK, properties and targets were used.

🔗 Follow-ups the interviewer may ask

  1. When: The candidate mentions an SDK mismatch or global.json. Why: SDK resolution is the most common root cause of IDE and CI mismatches.
    How to answer

    The dotnet host looks for a global.json from the current folder upwards. If there isn't one, it uses the latest installed SDK, even a preview. If there is one, it reads sdk.version and applies the rollForward policy to choose from the installed SDKs. With a version and no policy, the default is latestPatch, meaning the same feature band with the newest patch. allowPrerelease controls whether previews count. If nothing matches, every SDK command fails. I pin the SDK in every repo so developers, IDEs and CI build with the same compiler, analysers and defaults. dotnet --info shows which SDK was picked and why.

  2. When: The candidate says IntelliSense errors come from a different view of the project. Why: Design-time builds are MSBuild runs, so knowing properties, items and targets explains why the IDE's view can differ from the real build.
    How to answer

    MSBuild is the build engine under dotnet build, Visual Studio and Rider, and a .csproj is an MSBuild file. Properties are named values such as $(Configuration). Items are lists with metadata, such as @(Compile) holding every .cs file. Targets are named steps, ordered with DependsOnTargets, BeforeTargets and AfterTargets. Each target runs tasks, the real units of work, such as Csc to compile or Copy. The build has two phases. Evaluation reads imports, properties and items. Execution runs the targets. Targets that declare Inputs and Outputs are skipped when nothing has changed, which is what makes builds incremental.

🛠 Real-world problems: how you handle them

C# 14 squiggles in the IDE while CI is green after a .NET 10 upgrade
Situation
An order-processing service moved from net9.0 to net10.0 and started using C# 14 extension members. CI on hosted agents with the .NET 10 SDK was green, but about half the developers saw red squiggles and could not use IntelliSense on the new code.
Signals
Errors appeared under *IntelliSense only* in the Visual Studio Error List but not under *Build only*. `dotnet build` from a terminal succeeded on the same machines. Rider users on an older version saw similar errors.
Investigation
Ran `dotnet --version` and `dotnet --list-sdks` on affected machines: the CLI picked the .NET 10 SDK, but the affected developers were still on Visual Studio 2022, which does not support .NET 10. Checked Rider's About box and toolset settings for the Rider users. Confirmed there was no `global.json` and no documented minimum IDE version.
Resolution
Immediate: affected developers upgraded to Visual Studio 2026 and a current Rider release, then deleted `.vs/` and `obj/` folders. Long term: added `global.json` pinning SDK 10.0.100 with `rollForward: latestFeature`, documented minimum IDE versions in the README, and added the Visual Studio 2026 requirement to the `.vsconfig` rollout notes.
Prevention
Upgrade checklists for a new .NET version now include IDE versions. `global.json` makes SDK resolution explicit, and a short onboarding script prints `dotnet --info` and checks the IDE version.

How to tell it (STAR)

**Situation:** After we moved our [order-processing service] to .NET 10, CI was green but about half the team had IntelliSense errors on the new C# 14 code. **Task:** I needed to find out why the IDE and CI disagreed and stop it recurring. **Action:** I used the Error List filter to show the errors were IntelliSense-only, compared `dotnet --version` with each developer's IDE version, and found they were still on Visual Studio 2022, which does not support .NET 10. I got everyone onto Visual Studio 2026 or a current Rider, added `global.json`, and documented minimum IDE versions. **Result:** The phantom errors disappeared within a day and we had no repeat on the next upgrade [add your own numbers, such as hours saved or tickets avoided].

↩ Usually asked after

More in IDEs and Editors

Last updated 1 Nov 2026.

🌐 Sangam's Webring

⏪ Previous 🏠 Main Next ⏩
💬 Chat with me