Skip to content

[Bug] Static binary assets (images) corrupted by storageproxy after deployment #316

@DTR-fforest

Description

@DTR-fforest

Description

After deploying a Code App with npx power-apps push, static binary assets (JPG, PNG) included in the Vite build output (dist/) are served corrupted by the storageproxy. The files return HTTP 200 with the correct Content-Type header, but the response body is larger than the original file and unrenderable. Text-based assets (JS, CSS, HTML, SVG) are unaffected.

Steps to Reproduce

  1. Create a Code App with @microsoft/power-apps-vite
  2. Place an image in src/assets/ (e.g., a 196KB JPG) and import it in a component:
    import heroImg from '../assets/Splash.jpg';
    // ...
    <img src={heroImg} alt="Hero" />
  3. Build with npm run build — Vite emits the image to dist/assets/Splash-<hash>.jpg
  4. Deploy with npx power-apps push
  5. Open the deployed app and inspect the image request in DevTools (Network tab)

Expected Behavior

The image file should be served with its original byte content and render correctly in the browser.

Actual Behavior

  • The image returns HTTP 200 OK with Content-Type: image/jpeg (correct)
  • The Content-Length is larger than the original file
  • The image does not render (broken image icon in <img>, empty space in CSS background-image)
  • Opening the image URL directly in a new browser tab also shows a broken image

Evidence

File Original size Served Content-Length Ratio Renders?
Splash.jpg (196KB JPG) 195,725 bytes 351,508 bytes 1.80x No
test-pixel.png (minimal 1x1 PNG) 70 bytes 92 bytes 1.31x No
index.js (JS bundle) 198,310 bytes (correct) 1.00x Yes
index.css (CSS) 4,870 bytes (correct) 1.00x Yes
vite.svg (SVG) 1,497 bytes (correct) 1.00x Yes

The inflation ratio varies by file, which is consistent with binary content being re-encoded as UTF-8 text (bytes >127 become multi-byte sequences, with the inflation depending on the byte distribution of each file).

Workaround

Force Vite to inline all images as base64 data URLs by setting assetsInlineLimit in vite.config.ts:

export default defineConfig({
  plugins: [react(), powerApps()],
  build: {
    assetsInlineLimit: 300000, // Inline images as base64 to bypass storageproxy corruption
  },
});

This embeds the image directly in the JS bundle, avoiding the storageproxy serving path entirely. This works but increases bundle size (~1.33x per image) and does not scale for apps with many or large images.

Environment

  • PAC CLI: 2.5.1+gab954cf
  • @microsoft/power-apps: ^1.0.17
  • @microsoft/power-apps-vite: ^1.0.2
  • @microsoft/power-apps-cli: ^0.10.0
  • Vite: ^7.2.4
  • React: ^19.2.0
  • OS: Windows 11 Enterprise
  • Browser: Chrome/Edge (latest)
  • Power Platform region: prod (Canada)

Related Issues

These issues involve binary corruption in the connector execution layer (JSON.stringify on binary data). The issue reported here may share a similar root cause (text encoding applied to binary content) but occurs in the static asset serving path (storageproxy), not the connector layer.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions