Skip to content

A pinned platform version is silently ignored — in platform and in platform_packages #1407

Description

@stevenmunn312-tech

Version: 2.5.21 (pip), Windows 11. Consumer is a FastAPI build helper that drives a
generated platformio.ini scaffold, one [env:*] per supported board.

Summary

Both PlatformIO spellings of "pin this platform to a version" are accepted without
complaint and then dropped:

[env:esp32]
platform = espressif32@6.5.0        ; version discarded
board = esp32dev
framework = arduino
platform_packages = platform-espressif32@6.5.0   ; entry discarded

The build succeeds and uses the const-pinned default platform. Nothing in the output
says the pin had no effect, so the sketch that comes out is not the one the ini asked
for and there is no signal to say so.

Where it happens

The platform key. Platform::from_platform_str
(crates/fbuild-core/src/lib.rs:150) lowercases the whole value and substring-matches
it:

} else if s.contains("espressif32") {
    Some(Self::Espressif32)

espressif32@6.5.0 contains espressif32, so it resolves to Espressif32 and
everything after the @ is gone. Every caller reaches the platform through this
function, so the version has nowhere else to be read.

The platform_packages key. parse_platform_packages_entry
(crates/fbuild-config/src/platform_packages.rs:90) documents and implements the same
outcome deliberately:

// Plain `name @ <version>` (no URL, no slash, no `#sha`) is a registry
// version pin, not an override we can act on.

That reasoning is sound — there is no registry resolver to hand it to. The issue is
that it returns None silently, which is indistinguishable from "no override was
requested".

There is warning machinery for exactly this shape of problem in
crates/fbuild-config/src/pio_env.rs ("unsupported and ignored" / "recognized but
no-op"), but it covers PLATFORMIO_* environment variables only, not ini keys.

Why it matters to us

Pinning the ESP32 Arduino core is the fix for a real hardware problem: IDF 5 removed
I2S LCD mode, the new and legacy I2S drivers cannot coexist, and core 2.0.17 is the last
version that works for the audio path we generate. When the pin is silently ignored, the
resulting failure appears on the bench as an audio fault, and the ini says the opposite
of what was built. A pin that quietly does nothing costs more debugging time than a pin
that is refused outright.

What does work, and is worth documenting

The URL forms of platform_packages are honoured for ESP32 —
resolve_pioarduino_packages
(crates/fbuild-build-esp/src/esp32/orchestrator/packages.rs) resolves overrides for
both platform-espressif32 and framework-arduinoespressif32, per #672:

platform_packages =
    platform-espressif32@https://github.com/pioarduino/platform-espressif32/archive/<sha>.tar.gz

That is a genuinely good escape hatch and it solved our problem once we found it. It is
not obvious from the outside that the URL form works while the version form does not.

Possible resolutions, cheapest first

  1. Warn and continue. When a platform value carries an @<version> suffix, or a
    platform_packages entry is a bare version pin, say so on stderr and name the
    version actually used. This alone removes the failure mode: the pin still does
    nothing, but nobody is misled about it.
  2. Point at the escape hatch in that warning — one line naming the URL form.
  3. Honour registry version pins, which needs a registry resolver and is a feature
    rather than a fix. Only worth it if that resolver is wanted for other reasons.

We would take (1) happily; the silence is the whole problem, not the missing feature.

Offer

We build on Windows 11 against ESP32-S3, classic ESP32 and ESP8266 daily and are glad to
test a branch on any of them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions